staticfx 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- staticfx-2.0.0/CHANGELOG.md +73 -0
- staticfx-2.0.0/CONTRIBUTING.md +71 -0
- staticfx-2.0.0/LICENSE +21 -0
- staticfx-2.0.0/MANIFEST.in +9 -0
- staticfx-2.0.0/PKG-INFO +164 -0
- staticfx-2.0.0/README.md +130 -0
- staticfx-2.0.0/docs/ARCHITECTURE.md +150 -0
- staticfx-2.0.0/docs/EFFECT_FORMAT.md +392 -0
- staticfx-2.0.0/docs/RELEASING.md +58 -0
- staticfx-2.0.0/docs/STUDIO.md +98 -0
- staticfx-2.0.0/docs/USAGE.md +208 -0
- staticfx-2.0.0/docs/WRITING_EFFECTS.md +145 -0
- staticfx-2.0.0/examples/cell_division.sfx +38 -0
- staticfx-2.0.0/examples/ion_storm.sfx +45 -0
- staticfx-2.0.0/examples/neon_mandala.sfx +53 -0
- staticfx-2.0.0/pyproject.toml +89 -0
- staticfx-2.0.0/setup.cfg +4 -0
- staticfx-2.0.0/staticfx/__init__.py +3 -0
- staticfx-2.0.0/staticfx/__main__.py +5 -0
- staticfx-2.0.0/staticfx/app/__init__.py +1 -0
- staticfx-2.0.0/staticfx/app/app.py +335 -0
- staticfx-2.0.0/staticfx/app/keymap.py +163 -0
- staticfx-2.0.0/staticfx/app/player.py +143 -0
- staticfx-2.0.0/staticfx/app/session.py +97 -0
- staticfx-2.0.0/staticfx/cli/__init__.py +20 -0
- staticfx-2.0.0/staticfx/cli/commands.py +293 -0
- staticfx-2.0.0/staticfx/cli/parser.py +185 -0
- staticfx-2.0.0/staticfx/core/__init__.py +1 -0
- staticfx-2.0.0/staticfx/core/clock.py +30 -0
- staticfx-2.0.0/staticfx/core/color.py +89 -0
- staticfx-2.0.0/staticfx/core/frame.py +85 -0
- staticfx-2.0.0/staticfx/core/glyphs.py +15 -0
- staticfx-2.0.0/staticfx/core/keys.py +116 -0
- staticfx-2.0.0/staticfx/core/renderer.py +84 -0
- staticfx-2.0.0/staticfx/core/terminal.py +148 -0
- staticfx-2.0.0/staticfx/effects/__init__.py +1 -0
- staticfx-2.0.0/staticfx/effects/base.py +88 -0
- staticfx-2.0.0/staticfx/effects/builtin/__init__.py +203 -0
- staticfx-2.0.0/staticfx/effects/builtin/fields.py +404 -0
- staticfx-2.0.0/staticfx/effects/builtin/geometry.py +77 -0
- staticfx-2.0.0/staticfx/effects/builtin/particles.py +623 -0
- staticfx-2.0.0/staticfx/effects/builtin/shapes.py +255 -0
- staticfx-2.0.0/staticfx/effects/builtin/signals.py +298 -0
- staticfx-2.0.0/staticfx/effects/builtin/simulations.py +439 -0
- staticfx-2.0.0/staticfx/effects/builtin/terminal.py +362 -0
- staticfx-2.0.0/staticfx/effects/curated.py +16 -0
- staticfx-2.0.0/staticfx/effects/engine/__init__.py +11 -0
- staticfx-2.0.0/staticfx/effects/engine/effect.py +267 -0
- staticfx-2.0.0/staticfx/effects/engine/filters.py +115 -0
- staticfx-2.0.0/staticfx/effects/engine/generate.py +203 -0
- staticfx-2.0.0/staticfx/effects/engine/layers.py +396 -0
- staticfx-2.0.0/staticfx/effects/engine/recipe.py +215 -0
- staticfx-2.0.0/staticfx/effects/engine/schema.py +87 -0
- staticfx-2.0.0/staticfx/effects/engine/warps.py +203 -0
- staticfx-2.0.0/staticfx/effects/registry.py +103 -0
- staticfx-2.0.0/staticfx/effects/spec.py +51 -0
- staticfx-2.0.0/staticfx/integrations.py +48 -0
- staticfx-2.0.0/staticfx/library/__init__.py +1 -0
- staticfx-2.0.0/staticfx/library/config.py +122 -0
- staticfx-2.0.0/staticfx/library/effects.py +159 -0
- staticfx-2.0.0/staticfx/library/files.py +44 -0
- staticfx-2.0.0/staticfx/library/legacy.py +180 -0
- staticfx-2.0.0/staticfx/library/looks.py +134 -0
- staticfx-2.0.0/staticfx/postfx.py +78 -0
- staticfx-2.0.0/staticfx/py.typed +0 -0
- staticfx-2.0.0/staticfx/themes.py +162 -0
- staticfx-2.0.0/staticfx/ui/__init__.py +1 -0
- staticfx-2.0.0/staticfx/ui/browser.py +269 -0
- staticfx-2.0.0/staticfx/ui/dialogs.py +95 -0
- staticfx-2.0.0/staticfx/ui/help.py +99 -0
- staticfx-2.0.0/staticfx/ui/pickers.py +221 -0
- staticfx-2.0.0/staticfx/ui/play.py +213 -0
- staticfx-2.0.0/staticfx/ui/screen.py +39 -0
- staticfx-2.0.0/staticfx/ui/settings.py +262 -0
- staticfx-2.0.0/staticfx/ui/studio.py +433 -0
- staticfx-2.0.0/staticfx/ui/widgets.py +196 -0
- staticfx-2.0.0/staticfx.egg-info/PKG-INFO +164 -0
- staticfx-2.0.0/staticfx.egg-info/SOURCES.txt +100 -0
- staticfx-2.0.0/staticfx.egg-info/dependency_links.txt +1 -0
- staticfx-2.0.0/staticfx.egg-info/entry_points.txt +2 -0
- staticfx-2.0.0/staticfx.egg-info/requires.txt +5 -0
- staticfx-2.0.0/staticfx.egg-info/top_level.txt +1 -0
- staticfx-2.0.0/tests/conftest.py +49 -0
- staticfx-2.0.0/tests/fixtures/v1_config.json +24 -0
- staticfx-2.0.0/tests/fixtures/v1_looks.json +17 -0
- staticfx-2.0.0/tests/fixtures/v1_plugin.sfx +17 -0
- staticfx-2.0.0/tests/fixtures/v1_studio_effect.sfx +115 -0
- staticfx-2.0.0/tests/pty_session.py +174 -0
- staticfx-2.0.0/tests/test_app.py +226 -0
- staticfx-2.0.0/tests/test_cli.py +131 -0
- staticfx-2.0.0/tests/test_core.py +148 -0
- staticfx-2.0.0/tests/test_details.py +203 -0
- staticfx-2.0.0/tests/test_docs.py +78 -0
- staticfx-2.0.0/tests/test_effects.py +83 -0
- staticfx-2.0.0/tests/test_engine.py +110 -0
- staticfx-2.0.0/tests/test_library.py +191 -0
- staticfx-2.0.0/tests/test_terminal.py +120 -0
- staticfx-2.0.0/tests/test_ui.py +279 -0
- staticfx-2.0.0/tools/curate.py +144 -0
- staticfx-2.0.0/tools/demo.py +96 -0
- staticfx-2.0.0/tools/gen_docs.py +82 -0
- staticfx-2.0.0/tools/screenshot.py +120 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 2.0.0 (2026-11-07)
|
|
4
|
+
|
|
5
|
+
A rewrite. Your settings, favourites, looks and Studio effects carry over
|
|
6
|
+
automatically.
|
|
7
|
+
|
|
8
|
+
### New
|
|
9
|
+
|
|
10
|
+
- An effect browser with groups (Favourites, Recent, My Effects, Gallery,
|
|
11
|
+
seven built-in categories, Generated), search that ranks name matches first,
|
|
12
|
+
and live preview beside the list.
|
|
13
|
+
- A Gallery of 47 of the best generated effects, picked by hand.
|
|
14
|
+
- A settings screen (`o`): frame rate, character set, colour mode,
|
|
15
|
+
auto-cycle interval, and rebinding any key, with conflict warnings.
|
|
16
|
+
- A welcome card on first run, an optional status bar (`i`), and a key hint
|
|
17
|
+
line on start-up.
|
|
18
|
+
- In the Studio, every control has a real name and range, with a one-line
|
|
19
|
+
explanation of the selected setting; save as a copy (`a`); unlimited undo.
|
|
20
|
+
- Subcommands: `list`, `themes`, `looks`, `new`, `import`, `export`,
|
|
21
|
+
`render`, `fetch`, `doctor`. The 1.x flags still work.
|
|
22
|
+
- `staticfx doctor` checks your terminal and saved files and renders
|
|
23
|
+
every effect once.
|
|
24
|
+
- 26 themes, up from 13, including takes on Dracula, Nord, Gruvbox,
|
|
25
|
+
Solarized, Catppuccin and Tokyo Night. The theme menu shows each palette.
|
|
26
|
+
- Plain keys everywhere: menus no longer need Ctrl combinations: in the
|
|
27
|
+
browser `/` searches and `f`, `e`, `n`, `d` act on the highlighted effect.
|
|
28
|
+
Letters work with or without Shift, and every menu closes with `q`.
|
|
29
|
+
- Built-in looks reworked into twelve, each with a description.
|
|
30
|
+
- Meteor Shower has a twinkling sky; Fireworks fill large terminals.
|
|
31
|
+
- Docs: usage guide, Studio guide, file format, writing effects, architecture.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- One procedural engine: 1.x had two (`proc_*` and `gen_*`). The
|
|
36
|
+
`gen_*` effects are gone; favourites pointing at them are dropped
|
|
37
|
+
quietly. `proc_*` effects look the same as before.
|
|
38
|
+
- One `.sfx` format (version 3) with readable keys; 1.x Studio files
|
|
39
|
+
(version 2) and 1.x plugins are converted when read; old plugins are copied
|
|
40
|
+
into My Effects once.
|
|
41
|
+
- An automated quality gate removes 8 generated effects that were blank,
|
|
42
|
+
frozen, or a solid wall.
|
|
43
|
+
- Strobe is hidden until you allow flashing in Settings, and the theme
|
|
44
|
+
menu never previews it unless you have.
|
|
45
|
+
- The 1.x key that cycled rainbow and strobe is gone: Rainbow is a normal theme now. The old
|
|
46
|
+
"rainbow" overlay is called **recolour** (`w`) and keeps the effect's
|
|
47
|
+
shading.
|
|
48
|
+
- Presets and hacker scenes are merged into **looks**.
|
|
49
|
+
- The theme `monochrome` is now `mono` (the old name still works).
|
|
50
|
+
- Only rows that changed are redrawn each frame.
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
|
|
54
|
+
- A deleted effect or an unknown theme in `config.json` no longer stops
|
|
55
|
+
StaticFX from starting; any bad setting is ignored with a message.
|
|
56
|
+
- Ctrl-C in the Studio asks before discarding your work instead of quitting.
|
|
57
|
+
- Ctrl-Z suspends cleanly and restores the screen on `fg`.
|
|
58
|
+
- A user effect named like a built-in (`plasma`) no longer hides the
|
|
59
|
+
built-in on the command line.
|
|
60
|
+
- Plugin effects deleted in the menu came back on restart.
|
|
61
|
+
- Hand-edited config values of the wrong type were accepted silently.
|
|
62
|
+
- Below 40×12, a "terminal too small" message replaces menus that used to
|
|
63
|
+
draw over each other.
|
|
64
|
+
- Glyphs outside the terminal's character set could appear in ASCII mode.
|
|
65
|
+
|
|
66
|
+
### Removed
|
|
67
|
+
|
|
68
|
+
- The `gen_*` engine and the hidden `--plugin-dir` option.
|
|
69
|
+
|
|
70
|
+
## 1.0.0
|
|
71
|
+
|
|
72
|
+
First release: 50 built-in effects, 2,000 procedural effects in two
|
|
73
|
+
families, themes, looks, the Effect Studio and `.sfx` sharing.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for wanting to help. Bug reports, new effects and fixes are all
|
|
4
|
+
welcome.
|
|
5
|
+
|
|
6
|
+
## Setting up
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
git clone https://github.com/ethanlabs101/StaticFX && cd StaticFX
|
|
10
|
+
python3 -m venv .venv && . .venv/bin/activate
|
|
11
|
+
pip install -e '.[dev]'
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
StaticFX itself has no dependencies; those three are only for development.
|
|
15
|
+
The scripts in `tools/` also need Pillow (and `tools/demo.py` needs ffmpeg).
|
|
16
|
+
|
|
17
|
+
## Before you open a pull request
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pytest # everything, including real-terminal tests
|
|
21
|
+
ruff check . && ruff format --check .
|
|
22
|
+
mypy
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
CI runs the same on Linux and macOS with Python 3.10 to 3.13.
|
|
26
|
+
|
|
27
|
+
## Where things go
|
|
28
|
+
|
|
29
|
+
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) maps the code. In short:
|
|
30
|
+
|
|
31
|
+
- A new hand-written effect: [docs/WRITING_EFFECTS.md](docs/WRITING_EFFECTS.md).
|
|
32
|
+
- A new layer, warp or filter for the engine: add a function and a `Kind`
|
|
33
|
+
entry in `staticfx/effects/engine/layers.py` (or `warps.py`,
|
|
34
|
+
`filters.py`), then run `python tools/gen_docs.py` to update the format
|
|
35
|
+
reference. The Studio picks it up by itself.
|
|
36
|
+
- A new screen: subclass `Screen` in `staticfx/ui/`, give it a `help` tuple,
|
|
37
|
+
and add a test in `tests/test_ui.py`. It gets drawn at the minimum terminal
|
|
38
|
+
size and in ASCII mode automatically if you add it to `OPENERS` there.
|
|
39
|
+
- A new main-view key: add the action to `ACTIONS` and a default to
|
|
40
|
+
`DEFAULT_KEYS` in `staticfx/app/keymap.py`, and its handler in
|
|
41
|
+
`PlayScreen.actions`. A test checks the three agree, and another checks the
|
|
42
|
+
usage guide mentions it.
|
|
43
|
+
|
|
44
|
+
## Things that need care
|
|
45
|
+
|
|
46
|
+
- **Generated effects must not change by accident.** `test_engine.py`
|
|
47
|
+
fingerprints all 1,000 recipes. If you change `generate.py` or the
|
|
48
|
+
maths behind an existing layer, warp or filter, the fingerprint changes and
|
|
49
|
+
everyone's `proc_NNN` favourites point at different pictures. Do it only on
|
|
50
|
+
purpose, update the fingerprint, rerun `python tools/curate.py`, and note it
|
|
51
|
+
in the changelog.
|
|
52
|
+
- **Effect keys are forever.** They're stored in favourites, looks and
|
|
53
|
+
scripts. Rename the label, never the key.
|
|
54
|
+
- **Saved files must stay readable.** If you change the `.sfx` format or
|
|
55
|
+
`config.json`, bump the version and keep reading the old one (see
|
|
56
|
+
`library/legacy.py` and `config._migrate`).
|
|
57
|
+
- **Nothing may stop the app from starting.** Bad files and values are
|
|
58
|
+
reported and skipped, never raised.
|
|
59
|
+
|
|
60
|
+
## Style
|
|
61
|
+
|
|
62
|
+
`ruff format` decides formatting (100 columns). Beyond that: write code for
|
|
63
|
+
the next person to read, keep functions short, name things for what they
|
|
64
|
+
mean, and comment on *why*, not *what*. Docstrings on modules, classes and
|
|
65
|
+
anything non-obvious; not on every getter.
|
|
66
|
+
|
|
67
|
+
## Reporting a bug
|
|
68
|
+
|
|
69
|
+
Please include the output of `staticfx doctor`, your terminal and OS, and
|
|
70
|
+
what you pressed. If an effect looks wrong, `staticfx render EFFECT --ansi
|
|
71
|
+
--seed 1 --out frame.txt` captures it exactly.
|
staticfx-2.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ethangrames04
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# The source distribution carries the tests, docs and examples so it can be
|
|
2
|
+
# checked and repackaged on its own. Screenshots stay on GitHub.
|
|
3
|
+
include CHANGELOG.md CONTRIBUTING.md
|
|
4
|
+
graft docs
|
|
5
|
+
graft examples
|
|
6
|
+
graft tests
|
|
7
|
+
graft tools
|
|
8
|
+
prune assets
|
|
9
|
+
global-exclude __pycache__ *.py[cod]
|
staticfx-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: staticfx
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Animated ASCII effects for your terminal, with a studio for making your own
|
|
5
|
+
Author: ethanlabs101
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ethanlabs101/StaticFX
|
|
8
|
+
Project-URL: Documentation, https://github.com/ethanlabs101/StaticFX/blob/main/docs/USAGE.md
|
|
9
|
+
Project-URL: Changelog, https://github.com/ethanlabs101/StaticFX/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Issues, https://github.com/ethanlabs101/StaticFX/issues
|
|
11
|
+
Keywords: terminal,ascii,animation,cmatrix,screensaver,tui,ascii-art
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Artistic Software
|
|
24
|
+
Classifier: Topic :: Terminals
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
32
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# StaticFX
|
|
36
|
+
|
|
37
|
+
Animated ASCII effects for your terminal. Think `cmatrix`, but with a
|
|
38
|
+
thousand more effects, live theme switching, and a studio for making your own.
|
|
39
|
+
|
|
40
|
+

|
|
41
|
+
|
|
42
|
+
Pure Python, no dependencies, runs in any modern terminal on Linux, macOS
|
|
43
|
+
and WSL.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
You need Python 3.10 or newer.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pipx install staticfx
|
|
51
|
+
staticfx
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
(`pip install staticfx` works too; [pipx](https://pipx.pypa.io) just keeps it in
|
|
55
|
+
its own environment.) To try it without installing anything:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/ethanlabs101/StaticFX
|
|
59
|
+
cd StaticFX
|
|
60
|
+
python3 -m staticfx
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## The 30-second tour
|
|
64
|
+
|
|
65
|
+
Key | Does
|
|
66
|
+
--- | ---
|
|
67
|
+
`←` `→` | Previous / next effect
|
|
68
|
+
`m` | Browse and search every effect, with live preview
|
|
69
|
+
`t` | Change the colour theme
|
|
70
|
+
`l` | Looks: effect + theme + filters, saved under a name
|
|
71
|
+
`n` | Make your own effect in the Studio
|
|
72
|
+
`f` | Favourite
|
|
73
|
+
`a` | Auto-cycle (screensaver mode)
|
|
74
|
+
`?` | Every key
|
|
75
|
+
`q` | Quit
|
|
76
|
+
|
|
77
|
+
Everything is remappable in Settings (`o`). The full guide is in
|
|
78
|
+
[docs/USAGE.md](https://github.com/ethanlabs101/StaticFX/blob/main/docs/USAGE.md).
|
|
79
|
+
|
|
80
|
+
## What's inside
|
|
81
|
+
|
|
82
|
+
There are 50 hand-written effects in seven groups. Rain: the classic, plus
|
|
83
|
+
binary, hex and glitch versions. Particles: snow, embers, fireworks, orbits.
|
|
84
|
+
Space: a starfield, a galaxy, a black hole, a wormhole. Waves and fields:
|
|
85
|
+
plasma, aurora, a lava lamp, a synthwave grid. Geometry: a tumbling cube, a 4D
|
|
86
|
+
tesseract, spirographs. Simulations: Game of Life, Langton's ant, fire, a maze
|
|
87
|
+
that carves itself. Retro tech: boot screens, decryption, circuits, TV static.
|
|
88
|
+
|
|
89
|
+
On top of those are 992 generated effects. Each one is a recipe of layered
|
|
90
|
+
patterns (spirals, Julia and Mandelbrot fractals, Voronoi cells, metaballs,
|
|
91
|
+
noise), warps (kaleidoscope, swirl, tile, fold) and filters. They're seeded,
|
|
92
|
+
so `proc_042` is the same effect for everyone, forever. An automated quality
|
|
93
|
+
check weeds out the duds, and 47 hand-picked ones live in the Gallery.
|
|
94
|
+
|
|
95
|
+
Then there are your own. The Studio remixes any generated effect or starts
|
|
96
|
+
from scratch, with a live preview and undo, and saves small JSON files you
|
|
97
|
+
can share.
|
|
98
|
+
|
|
99
|
+
You also get:
|
|
100
|
+
|
|
101
|
+
- **26 colour themes**: originals like Matrix, Inferno and Vaporwave, takes on
|
|
102
|
+
popular editor schemes (Dracula, Nord, Gruvbox, Catppuccin, Tokyo Night), an
|
|
103
|
+
animated rainbow, and Strobe if you opt in (it's off by default for
|
|
104
|
+
photosensitivity reasons)
|
|
105
|
+
- filters that work on anything: CRT scanlines, glitch, rainbow recolour
|
|
106
|
+
- looks, which save an effect with its theme, speed and filters so you can
|
|
107
|
+
recall it with one key (a dozen come built in)
|
|
108
|
+
|
|
109
|
+

|
|
110
|
+
|
|
111
|
+

|
|
112
|
+
|
|
113
|
+
## Make your own
|
|
114
|
+
|
|
115
|
+
Press `n` for a new effect, or highlight a generated one in the browser and
|
|
116
|
+
press `e` to remix it. Arrow keys change things; `s` saves it to
|
|
117
|
+
**My Effects**.
|
|
118
|
+
|
|
119
|
+

|
|
120
|
+
|
|
121
|
+
See [docs/STUDIO.md](https://github.com/ethanlabs101/StaticFX/blob/main/docs/STUDIO.md) for what every control does, and
|
|
122
|
+
[docs/EFFECT_FORMAT.md](https://github.com/ethanlabs101/StaticFX/blob/main/docs/EFFECT_FORMAT.md) for the file format if you'd
|
|
123
|
+
rather write recipes by hand.
|
|
124
|
+
|
|
125
|
+
## Command line
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
staticfx -e plasma -t ocean # start on an effect and theme
|
|
129
|
+
staticfx --look "Synthwave" # start from a look
|
|
130
|
+
staticfx --auto 30 --duration 600 # screensaver: new effect every 30s, quit after 10 min
|
|
131
|
+
staticfx list fire # search effects
|
|
132
|
+
staticfx render galaxy --size 80x24 # print one frame (add --ansi for colour)
|
|
133
|
+
staticfx fetch # fastfetch/neofetch output over an effect
|
|
134
|
+
staticfx new "Night Drive" # create a random effect in My Effects
|
|
135
|
+
staticfx export my_night_drive nd.sfx # share it
|
|
136
|
+
staticfx doctor # check your setup
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`staticfx --help` and `staticfx COMMAND --help` list everything.
|
|
140
|
+
|
|
141
|
+
## Docs
|
|
142
|
+
|
|
143
|
+
- [Usage](https://github.com/ethanlabs101/StaticFX/blob/main/docs/USAGE.md): every key, the browser, themes, looks, settings,
|
|
144
|
+
command line, troubleshooting
|
|
145
|
+
- [The Studio](https://github.com/ethanlabs101/StaticFX/blob/main/docs/STUDIO.md)
|
|
146
|
+
- [Effect file format](https://github.com/ethanlabs101/StaticFX/blob/main/docs/EFFECT_FORMAT.md)
|
|
147
|
+
- [Writing a built-in effect](https://github.com/ethanlabs101/StaticFX/blob/main/docs/WRITING_EFFECTS.md) in Python
|
|
148
|
+
- [Architecture](https://github.com/ethanlabs101/StaticFX/blob/main/docs/ARCHITECTURE.md): how it fits together, and why
|
|
149
|
+
- [Releasing](https://github.com/ethanlabs101/StaticFX/blob/main/docs/RELEASING.md): publishing a new version to PyPI
|
|
150
|
+
|
|
151
|
+
## Development
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
git clone https://github.com/ethanlabs101/StaticFX && cd StaticFX
|
|
155
|
+
python3 -m pip install -e '.[dev]'
|
|
156
|
+
python3 -m pytest # ~650 tests, about a minute
|
|
157
|
+
ruff check . && ruff format --check . && mypy
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
See [CONTRIBUTING.md](https://github.com/ethanlabs101/StaticFX/blob/main/CONTRIBUTING.md) for how changes are made and checked.
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
[MIT](https://github.com/ethanlabs101/StaticFX/blob/main/LICENSE)
|
staticfx-2.0.0/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# StaticFX
|
|
2
|
+
|
|
3
|
+
Animated ASCII effects for your terminal. Think `cmatrix`, but with a
|
|
4
|
+
thousand more effects, live theme switching, and a studio for making your own.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
Pure Python, no dependencies, runs in any modern terminal on Linux, macOS
|
|
9
|
+
and WSL.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
You need Python 3.10 or newer.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pipx install staticfx
|
|
17
|
+
staticfx
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
(`pip install staticfx` works too; [pipx](https://pipx.pypa.io) just keeps it in
|
|
21
|
+
its own environment.) To try it without installing anything:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
git clone https://github.com/ethanlabs101/StaticFX
|
|
25
|
+
cd StaticFX
|
|
26
|
+
python3 -m staticfx
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## The 30-second tour
|
|
30
|
+
|
|
31
|
+
Key | Does
|
|
32
|
+
--- | ---
|
|
33
|
+
`←` `→` | Previous / next effect
|
|
34
|
+
`m` | Browse and search every effect, with live preview
|
|
35
|
+
`t` | Change the colour theme
|
|
36
|
+
`l` | Looks: effect + theme + filters, saved under a name
|
|
37
|
+
`n` | Make your own effect in the Studio
|
|
38
|
+
`f` | Favourite
|
|
39
|
+
`a` | Auto-cycle (screensaver mode)
|
|
40
|
+
`?` | Every key
|
|
41
|
+
`q` | Quit
|
|
42
|
+
|
|
43
|
+
Everything is remappable in Settings (`o`). The full guide is in
|
|
44
|
+
[docs/USAGE.md](https://github.com/ethanlabs101/StaticFX/blob/main/docs/USAGE.md).
|
|
45
|
+
|
|
46
|
+
## What's inside
|
|
47
|
+
|
|
48
|
+
There are 50 hand-written effects in seven groups. Rain: the classic, plus
|
|
49
|
+
binary, hex and glitch versions. Particles: snow, embers, fireworks, orbits.
|
|
50
|
+
Space: a starfield, a galaxy, a black hole, a wormhole. Waves and fields:
|
|
51
|
+
plasma, aurora, a lava lamp, a synthwave grid. Geometry: a tumbling cube, a 4D
|
|
52
|
+
tesseract, spirographs. Simulations: Game of Life, Langton's ant, fire, a maze
|
|
53
|
+
that carves itself. Retro tech: boot screens, decryption, circuits, TV static.
|
|
54
|
+
|
|
55
|
+
On top of those are 992 generated effects. Each one is a recipe of layered
|
|
56
|
+
patterns (spirals, Julia and Mandelbrot fractals, Voronoi cells, metaballs,
|
|
57
|
+
noise), warps (kaleidoscope, swirl, tile, fold) and filters. They're seeded,
|
|
58
|
+
so `proc_042` is the same effect for everyone, forever. An automated quality
|
|
59
|
+
check weeds out the duds, and 47 hand-picked ones live in the Gallery.
|
|
60
|
+
|
|
61
|
+
Then there are your own. The Studio remixes any generated effect or starts
|
|
62
|
+
from scratch, with a live preview and undo, and saves small JSON files you
|
|
63
|
+
can share.
|
|
64
|
+
|
|
65
|
+
You also get:
|
|
66
|
+
|
|
67
|
+
- **26 colour themes**: originals like Matrix, Inferno and Vaporwave, takes on
|
|
68
|
+
popular editor schemes (Dracula, Nord, Gruvbox, Catppuccin, Tokyo Night), an
|
|
69
|
+
animated rainbow, and Strobe if you opt in (it's off by default for
|
|
70
|
+
photosensitivity reasons)
|
|
71
|
+
- filters that work on anything: CRT scanlines, glitch, rainbow recolour
|
|
72
|
+
- looks, which save an effect with its theme, speed and filters so you can
|
|
73
|
+
recall it with one key (a dozen come built in)
|
|
74
|
+
|
|
75
|
+

|
|
76
|
+
|
|
77
|
+

|
|
78
|
+
|
|
79
|
+
## Make your own
|
|
80
|
+
|
|
81
|
+
Press `n` for a new effect, or highlight a generated one in the browser and
|
|
82
|
+
press `e` to remix it. Arrow keys change things; `s` saves it to
|
|
83
|
+
**My Effects**.
|
|
84
|
+
|
|
85
|
+

|
|
86
|
+
|
|
87
|
+
See [docs/STUDIO.md](https://github.com/ethanlabs101/StaticFX/blob/main/docs/STUDIO.md) for what every control does, and
|
|
88
|
+
[docs/EFFECT_FORMAT.md](https://github.com/ethanlabs101/StaticFX/blob/main/docs/EFFECT_FORMAT.md) for the file format if you'd
|
|
89
|
+
rather write recipes by hand.
|
|
90
|
+
|
|
91
|
+
## Command line
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
staticfx -e plasma -t ocean # start on an effect and theme
|
|
95
|
+
staticfx --look "Synthwave" # start from a look
|
|
96
|
+
staticfx --auto 30 --duration 600 # screensaver: new effect every 30s, quit after 10 min
|
|
97
|
+
staticfx list fire # search effects
|
|
98
|
+
staticfx render galaxy --size 80x24 # print one frame (add --ansi for colour)
|
|
99
|
+
staticfx fetch # fastfetch/neofetch output over an effect
|
|
100
|
+
staticfx new "Night Drive" # create a random effect in My Effects
|
|
101
|
+
staticfx export my_night_drive nd.sfx # share it
|
|
102
|
+
staticfx doctor # check your setup
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`staticfx --help` and `staticfx COMMAND --help` list everything.
|
|
106
|
+
|
|
107
|
+
## Docs
|
|
108
|
+
|
|
109
|
+
- [Usage](https://github.com/ethanlabs101/StaticFX/blob/main/docs/USAGE.md): every key, the browser, themes, looks, settings,
|
|
110
|
+
command line, troubleshooting
|
|
111
|
+
- [The Studio](https://github.com/ethanlabs101/StaticFX/blob/main/docs/STUDIO.md)
|
|
112
|
+
- [Effect file format](https://github.com/ethanlabs101/StaticFX/blob/main/docs/EFFECT_FORMAT.md)
|
|
113
|
+
- [Writing a built-in effect](https://github.com/ethanlabs101/StaticFX/blob/main/docs/WRITING_EFFECTS.md) in Python
|
|
114
|
+
- [Architecture](https://github.com/ethanlabs101/StaticFX/blob/main/docs/ARCHITECTURE.md): how it fits together, and why
|
|
115
|
+
- [Releasing](https://github.com/ethanlabs101/StaticFX/blob/main/docs/RELEASING.md): publishing a new version to PyPI
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
git clone https://github.com/ethanlabs101/StaticFX && cd StaticFX
|
|
121
|
+
python3 -m pip install -e '.[dev]'
|
|
122
|
+
python3 -m pytest # ~650 tests, about a minute
|
|
123
|
+
ruff check . && ruff format --check . && mypy
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
See [CONTRIBUTING.md](https://github.com/ethanlabs101/StaticFX/blob/main/CONTRIBUTING.md) for how changes are made and checked.
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
[MIT](https://github.com/ethanlabs101/StaticFX/blob/main/LICENSE)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
StaticFX is about 9,000 lines of Python (nearly half of it the effects themselves) with no
|
|
4
|
+
dependencies. This page is
|
|
5
|
+
the map: what lives where, what happens every frame, and why it's built the
|
|
6
|
+
way it is.
|
|
7
|
+
|
|
8
|
+
## Layers
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
cli/ parse the command line, run a subcommand
|
|
12
|
+
│
|
|
13
|
+
app/ the interactive app: settings, player, screen stack, run loop
|
|
14
|
+
│ ui/ screens (browser, Studio, settings, ...) and drawing helpers
|
|
15
|
+
│
|
|
16
|
+
effects/ what can be drawn: built-ins, the procedural engine, the registry
|
|
17
|
+
library/ what the user saves: settings, .sfx effects, looks
|
|
18
|
+
│
|
|
19
|
+
core/ terminal plumbing: colour, frames, rendering, keys, terminal modes
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Imports only point down this list. `core` knows nothing about effects;
|
|
23
|
+
`effects` knows nothing about the app; screens reach the app only through
|
|
24
|
+
the `App` object they're given. The one upward reference, `App` creating the
|
|
25
|
+
first `PlayScreen`, is deliberate: the app owns its screen stack.
|
|
26
|
+
|
|
27
|
+
## Modules
|
|
28
|
+
|
|
29
|
+
Path | What it does
|
|
30
|
+
--- | ---
|
|
31
|
+
`core/color.py` | `RGB` and the few colour operations effects need.
|
|
32
|
+
`core/frame.py` | `Frame`: a grid of `(char, colour)` cells. Spaces are transparent.
|
|
33
|
+
`core/renderer.py` | Encodes a frame as ANSI, writing only rows that changed since the last frame.
|
|
34
|
+
`core/keys.py` | Turns raw terminal bytes into key names (`up`, `ctrl-e`, `a`).
|
|
35
|
+
`core/terminal.py` | Takes over the terminal (alternate screen, raw-ish input) and always gives it back: on exit, exceptions, `SIGTERM`, and around `Ctrl-Z`.
|
|
36
|
+
`core/clock.py` | Frame pacing.
|
|
37
|
+
`themes.py` | Colour themes as 256-entry ramps, plus the animated Rainbow and Strobe.
|
|
38
|
+
`postfx.py` | The CRT, glitch and recolour filters applied to finished frames.
|
|
39
|
+
`effects/base.py` | The `Effect` base class and its contract.
|
|
40
|
+
`effects/builtin/` | The 50 hand-written effects, and `CATALOGUE`, which names and groups them.
|
|
41
|
+
`effects/engine/` | The procedural engine: `schema.py` (parameter descriptions), `layers.py`, `warps.py`, `filters.py`, `recipe.py` (the data model and its JSON form), `generate.py` (seed → recipe), `effect.py` (drawing a recipe).
|
|
42
|
+
`effects/registry.py` | Every playable effect in a stable order, and name lookup.
|
|
43
|
+
`effects/curated.py` | Which generated effects are excluded, and the Gallery.
|
|
44
|
+
`library/config.py` | `Settings` and a loader that never fails.
|
|
45
|
+
`library/effects.py` | Reading and writing `.sfx` files.
|
|
46
|
+
`library/legacy.py` | Converting StaticFX 1.x files.
|
|
47
|
+
`library/looks.py` | Saved looks and the built-in ones.
|
|
48
|
+
`app/app.py` | `App`: settings, library, player, screen stack, toasts, saving.
|
|
49
|
+
`app/player.py` | What's on screen: the effect, theme, speed, filters, and previews.
|
|
50
|
+
`app/keymap.py` | Main-view actions and their keys.
|
|
51
|
+
`app/session.py` | The real-terminal loop, and headless rendering.
|
|
52
|
+
`ui/screen.py` | The `Screen` base class.
|
|
53
|
+
`ui/widgets.py` | Box characters, colours, panels, scrolling lists.
|
|
54
|
+
`ui/play.py`, `browser.py`, `pickers.py`, `studio.py`, `settings.py`, `help.py`, `dialogs.py` | One file per screen.
|
|
55
|
+
`cli/parser.py`, `cli/commands.py` | Arguments, and one function per subcommand.
|
|
56
|
+
|
|
57
|
+
## One frame
|
|
58
|
+
|
|
59
|
+
`session.run` loops:
|
|
60
|
+
|
|
61
|
+
1. **Input.** `KeyReader` collects pending keys. `App.handle_key` gives each
|
|
62
|
+
one to the screen on top of the stack. `Ctrl-Z` is the exception: the app
|
|
63
|
+
asks the session to suspend.
|
|
64
|
+
2. **Resize.** If the terminal changed size, the frame, the player and every
|
|
65
|
+
effect are resized and the screen is redrawn from scratch.
|
|
66
|
+
3. **Update.** `App.update(dt)` advances the player (which advances the
|
|
67
|
+
effect, scaled by speed), every screen, the toast timer and auto-cycle.
|
|
68
|
+
4. **Draw.** `App.draw(frame)` asks the player to draw the effect and apply
|
|
69
|
+
filters, then draws each screen from the bottom up.
|
|
70
|
+
5. **Output.** `Renderer.diff` encodes the rows that changed; one `write`.
|
|
71
|
+
6. **Save.** If settings changed, they're written, at most once a second.
|
|
72
|
+
7. **Wait** for the next frame.
|
|
73
|
+
|
|
74
|
+
Nothing in `App` or the screens touches the terminal, which is why the test
|
|
75
|
+
suite can drive the whole app with key presses and inspect the frames.
|
|
76
|
+
|
|
77
|
+
## Decisions
|
|
78
|
+
|
|
79
|
+
**No curses.** `curses` would handle terminal modes, but it's not available
|
|
80
|
+
on every Python build, its colour support stops at 256 colours without
|
|
81
|
+
work, and it makes the app much harder to test. Writing ANSI directly is a
|
|
82
|
+
few hundred lines in `core/` and gives 24-bit colour everywhere.
|
|
83
|
+
|
|
84
|
+
**Signals off in the terminal.** The terminal is put in a mode where Ctrl-C
|
|
85
|
+
and Ctrl-Z arrive as keys rather than signals. Each screen decides what they
|
|
86
|
+
mean, so Ctrl-C in the Studio can ask before throwing away your work instead
|
|
87
|
+
of killing the program. Suspend is done by hand: restore the terminal, stop,
|
|
88
|
+
re-enter when resumed.
|
|
89
|
+
|
|
90
|
+
**Row-level diffing.** Only rows that changed since the last frame are
|
|
91
|
+
written. For busy effects that saves little (about 7% of bytes across the
|
|
92
|
+
built-ins, measured at 120×36), but a paused effect or a slow one costs
|
|
93
|
+
almost nothing to redraw. Cell-level diffing would save more on busy
|
|
94
|
+
effects, at the price of a cursor move per changed run and noticeably more
|
|
95
|
+
code in the hottest loop; it's the obvious next step if output volume ever
|
|
96
|
+
becomes the bottleneck.
|
|
97
|
+
|
|
98
|
+
**`RGB` is a `NamedTuple`.** Thousands of colours are created per frame;
|
|
99
|
+
tuples are the cheapest immutable, hashable value Python has.
|
|
100
|
+
|
|
101
|
+
**A screen stack.** Each mode (browser, Studio, a confirmation dialog) is a
|
|
102
|
+
`Screen` with `handle`, `update` and `draw`. The top one gets the keys.
|
|
103
|
+
Opening a dialog over the Studio is just a push; nothing else needs to know.
|
|
104
|
+
This replaced a single class with a long `if menu: ... elif studio: ...`
|
|
105
|
+
chain.
|
|
106
|
+
|
|
107
|
+
**One parameter schema.** Each layer, warp and filter kind declares its
|
|
108
|
+
parameters once (`Param` in `engine/schema.py`). That one description is used
|
|
109
|
+
to validate `.sfx` files, fill in defaults, build the Studio's controls and
|
|
110
|
+
generate the reference in `EFFECT_FORMAT.md`, so they can't drift apart.
|
|
111
|
+
|
|
112
|
+
**Generated effects never change.** `generate(seed)` draws its random values
|
|
113
|
+
in a fixed order, and a test fingerprints all 1,000 recipes. Favourites,
|
|
114
|
+
saved looks and scripts that say `proc_042` keep meaning the same picture.
|
|
115
|
+
Changing the generator on purpose means updating the fingerprint and saying
|
|
116
|
+
so in the changelog.
|
|
117
|
+
|
|
118
|
+
**A quality gate, not a hand filter.** `tools/curate.py` renders every
|
|
119
|
+
generated recipe and excludes the ones that are blank, frozen or a solid
|
|
120
|
+
wall. It's repeatable: rerun it after changing the engine. The Gallery, by
|
|
121
|
+
contrast, is picked by eye; taste doesn't automate well.
|
|
122
|
+
|
|
123
|
+
**Settings can't stop the app from starting.** Every value in `config.json`
|
|
124
|
+
is checked on its own; a bad one is replaced by its default with a message.
|
|
125
|
+
The same goes for `.sfx` files and looks: a broken file is skipped and
|
|
126
|
+
reported, never fatal. The last effect you played may have been deleted;
|
|
127
|
+
StaticFX says so and starts on Matrix Rain.
|
|
128
|
+
|
|
129
|
+
**Adaptive detail.** The engine samples the pattern on a grid of blocks
|
|
130
|
+
rather than every cell when the terminal is large, and in the interactive
|
|
131
|
+
app it also coarsens or refines that grid based on how long frames take.
|
|
132
|
+
Headless rendering (`staticfx render`) keeps full detail so output is
|
|
133
|
+
deterministic.
|
|
134
|
+
|
|
135
|
+
## Testing
|
|
136
|
+
|
|
137
|
+
`tests/` mirrors the layers:
|
|
138
|
+
|
|
139
|
+
File | Covers
|
|
140
|
+
--- | ---
|
|
141
|
+
`test_core.py` | Colours, frame clipping, renderer diffing, key decoding.
|
|
142
|
+
`test_engine.py` | The schema, recipe validation (including a fuzz test that corrupts real recipes), and the generated-effects fingerprint.
|
|
143
|
+
`test_effects.py` | Every built-in, and a sample of generated effects, at sizes from 1×1 to 250×70, with odd timesteps, in both character modes.
|
|
144
|
+
`test_library.py` | Settings, `.sfx` files, looks, and real files from StaticFX 1.x.
|
|
145
|
+
`test_app.py` | Startup, playing, favourites, looks, key bindings, saving.
|
|
146
|
+
`test_ui.py` | Every screen driven by key presses, and drawn at the minimum size and in ASCII mode.
|
|
147
|
+
`test_cli.py` | Every subcommand, and the 1.x flags.
|
|
148
|
+
`test_terminal.py` | The real program in a pseudo-terminal: quitting, Ctrl-C, Ctrl-Z, resizing, `SIGTERM`, a corrupt config.
|
|
149
|
+
`test_docs.py` | Generated docs are current and the README and guides match the code.
|
|
150
|
+
`test_details.py` | Filters, the fetch overlay, adaptive detail, name lookup, dialogs.
|