# Synesthete
Hear the state of your code in Sublime Text.
Synesthete plays your code. The music walks through it line by line on
recorded instruments, so every file has its own melody, and when the code
changes the music jumps to where it changed. How good the code is decides
how the music sounds: beautiful code is a harp over a cello section; worse
code moves to marimba, then piano in a minor key, then tubular bells and a
droning contrabass, until cursed code is a singing saw sliding over
trembling strings, gongs and bowed cymbals. Changes also get a short accent: rising if things got better,
falling if they got worse.
## Stages
| Health | Stage | Sound |
| --------- | --------- | ----------------------------------------------------------- |
| 0.90–1.00 | beautiful | harp in major pentatonic, glockenspiel, cello section |
| 0.75–0.90 | good | harp in major, pizzicato bass |
| 0.60–0.75 | decent | marimba in open fourths and fifths, pizzicato bass |
| 0.45–0.60 | meh | piano in minor, cello section |
| 0.30–0.45 | bad | sparse piano in Phrygian, tubular bells, sustained bass |
| 0.15–0.30 | awful | detuned piano clusters, tubular bells, cello tremolo, timpani |
| 0.00–0.15 | cursed | a singing saw over contrabass tremolo, gongs, bowed cymbal |
As things get worse the tempo slows, the timing loosens, notes drop out,
the tuning drifts and the room grows from a small hall into a cavern.
## How the code becomes music
Each line is one step. Its indentation sets how high it sits in the
stage's scale, so deeper code climbs; a hash of its text nudges the note,
so different lines make different melodies while identical lines sound
identical (duplicated code sounds repetitive); and its length sets how hard
it's played. Blank lines are rests. Comments ring on a second instrument,
lines that start functions bring in the bass, and lines the syntax
definition flags as broken sound a dissonant cluster as the music passes
them. Eight lines make a bar; each bar is rendered once and cached, so code
that hasn't changed costs nothing to play again.
The instruments are real recordings from
[VSCO 2 Community Edition](https://versilian-studios.com/vsco-community/),
which is public domain; see [samples/README.md](samples/README.md). The
singing saw, an almost pure tone, is synthesized.
## How code is judged
**Quality** starts at 1.0 and falls toward 0.3 as smells pile up: functions
longer than 40 lines, functions with more than 10 branches, code nested more
than four levels inside its function (lines inside brackets, such as
arguments, nested arrays or hash literals, continue an expression rather
than nest; blocks still nest), duplicated chunks, lines longer than your
widest ruler (not counting URLs, which can't be broken), trailing
whitespace, tabs mixed with spaces, and TODO, FIXME, XXX and HACK comments. Smells count in proportion to the file's size,
so one long function sinks a short file more than a long one. Mess alone
never drops below bad.
**Bugs** divide what's left: spans the syntax definition marks as `invalid`
(code it cannot parse) and brackets that never close, outside strings and
comments. One bug in beautiful code sounds meh, two bad, three awful, eight
cursed.
Syntax highlighting misses a lot of broken code, such as a Ruby class
without its `end`, so Synesthete also asks the language's own parser:
`ruby -c`, Python's `ast`, `node --check`, `bash -n` and `php -l`. None of
them run the code. A file that doesn't parse counts as at least three bugs.
Add other languages in the `syntax_checkers` setting.
Everything comes from Sublime's own syntax definitions (scopes such as
`entity.name.function` and `keyword.control.conditional`), so it works for
any language with a decent syntax. `Synesthete: Explain Score` shows what
went into the current score, and the status bar shows the stage.
## Listening to a file or a project
- **file** (default): the file you are looking at, as you type. While no
code file is open, the window's project plays instead.
- **project**: every source file in the window's folders, as it changes on
disk. Made for coding agents: you don't need to look at any file to hear
the agent work. The music walks through every file in the project, one
after another. Each file the agent writes plays an accent in that file's
stage, rising or falling with the change, and the music jumps to where it
changed, then walks on from there. The stage follows the whole project: quality
averaged by file size, with every bug in every file counted. Synesthete
checks for changes twice a second and skips whatever git ignores.
Switch with `Synesthete: Listen to File` and `Synesthete: Listen to Project`.
Synesthete follows you between windows and files, switching at the end of
the bar. When the window or file it's playing closes, it moves on to
whatever is open, and when nothing is, it fades out, the same as when you
quit.
## The map
`Synesthete: Show Map` opens a tab with a bird's-eye view of the code:
every file is a tile, grouped by folder, as wide as the file is long and
colored by its stage. A file that changes lights up and fades over ten
seconds, so you can watch an agent move through the project; broken files
carry a ⚠, and clicking a tile opens its file. Above the tiles, a timeline
shows the last ten minutes of health, with a tick for every change: green
when it got better, red when it got worse. In file mode the map shows the
open files.
## The visualizer
`Synesthete: Open Visualizer` opens a browser tab where you fly through a
tunnel made of your code: each file is a band of color around its walls, in
its stage's color, as wide as the file is long. How healthy the code is
decides how the flight feels. Beautiful code is a fast, smooth, neon flight
toward a bright light; as it gets worse the tunnel slows, twists and sways,
the colors bruise, and at the bottom the picture tears and splits and the
light at the end goes out. Every change sends light racing down the tunnel
from its file, green when it got better and red when it got worse. Nothing
flashes more than twice a second, the rings are kept soft, and the motion
calms down when macOS's Reduce Motion setting is on.
The page talks to Sublime through a small server on 127.0.0.1 that only
answers requests carrying the random token in the page's address. To try it
without Sublime, run `python3 tools/visualizer_demo.py` and open the address
it prints.
## The tiles
`Synesthete: Open Tiles` opens a browser tab with every file as a tile,
laid out in path order in one square, like a contribution graph, and
colored by its health, from green for beautiful through yellow and orange
to dark red for cursed. A file that changes glows and fades over a few seconds, ringed green
when it got better and red when it got worse; broken files carry a dot.
Hover a tile to see its file and score. It runs on the visualizer’s server,
and `python3 tools/visualizer_demo.py` prints its address too.
## Modes
- **ambient** (default): the code played continuously, plus the accents.
When the stage changes, the next bar starts right away.
- **chime**: only the accents, and a bar when the stage changes.
## Install
With [Package Control](https://packagecontrol.io): run `Package Control:
Install Package` and pick `Synesthete`.
By hand: link this folder into Sublime Text's `Packages` folder under the
name `Synesthete`. On macOS:
```bash
ln -s "$PWD" "$HOME/Library/Application Support/Sublime Text/Packages/Synesthete"
```
Then run `Synesthete: Play All Stages` from the command palette to hear the
current file in every stage.
Requires Sublime Text 4. Sound is played with `afplay` on macOS and `paplay`,
`pw-play`, or `aplay` on Linux. On Windows it uses `winsound`, which cannot
overlap sounds, so each sound cuts off the one before.
## Usage
Synesthete plays as soon as it’s installed:
- Open a code file to hear it change as you type. Open a folder without
opening a file to hear the whole project.
- Working with a coding agent? Run `Synesthete: Listen to Project` to hear
every file in the window’s folders as the agent changes them, whichever
file you’re looking at.
- Run `Synesthete: Open Visualizer` to fly through the tunnel,
`Synesthete: Open Tiles` to watch files glow as they change, or
`Synesthete: Show Map` to see every file at a glance.
- Run `Synesthete: Explain Score` to see why the code sounds the way it does.
- If continuous music is too much, `Synesthete: Chime Mode` plays only the
accents.
- `Synesthete: Toggle` turns it off, and it stays off until you turn it on
again.
## Commands
- `Synesthete: Toggle`
- `Synesthete: Listen to File` and `Synesthete: Listen to Project`
- `Synesthete: Ambient Mode` and `Synesthete: Chime Mode`
- `Synesthete: Play Now` plays a bar of the current code
- `Synesthete: Explain Score`
- `Synesthete: Show Map`
- `Synesthete: Open Visualizer`
- `Synesthete: Open Tiles`
- `Synesthete: Play All Stages`
- `Preferences: Synesthete Settings`
- `Preferences: Synesthete Key Bindings`
The same commands are under Tools > Synesthete.
Synesthete adds no key bindings. To toggle it with
ctrl+alt+s, run `Preferences: Synesthete Key
Bindings` and copy the example on the left to your key bindings on the right:
```json
{ "keys": ["ctrl+alt+s"], "command": "synesthete_toggle" }
```
## Tests
```bash
python3 -m unittest discover -s tests
```