Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
46 changes: 46 additions & 0 deletions docs/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# About Audio Sort

I created Audio Sort to "hear" what sorting algorithms sound like. You can watch
and listen to each algorithm at work, then edit its code to see how small changes
affect the result.

## Why it started in 2013

The project was also an excuse to experiment with relatively new web technologies:
[Web Audio](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API), responsive design with [Bootstrap 2](https://getbootstrap.com/2.3.2/), [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API), and [D3](https://d3js.org/).
Sorting gave me a way to bring them together in one browser experiment.

[Timbre.js](https://mohayonao.github.io/timbre.js/) handled the sound, D3 drew the visualizations, and Bootstrap made the
interface adapt to different screen sizes. Web Workers ran the sorting algorithms
without blocking the interface. Along with editable algorithms and MIDI export,
those pieces made Audio Sort a playground for learning about both sorting and
the web.

The [original project page](https://skratchdot.com/projects/audio-sort/) lists
the libraries and links to other sorting experiments.

## What changed in 2026

A bug report about **Edit Algorithm** brought me back to the project. The fix was
small: the editor assumed a particular format for `Function.toString()` output.
The breakage appears to date back to the 2019 ECMAScript changes to that output,
with a line break before the function arguments tripping up the old code.

Once that worked again, I decided to use the project to gain more experience
modernizing a legacy codebase with AI. That meant untangling the [jQuery](https://jquery.com/) soup,
separating settings and playback from the interface, and updating the libraries
and build tools.

[React](https://react.dev/) now renders the interface and charts, with [Tailwind CSS](https://tailwindcss.com/) and [shadcn](https://ui.shadcn.com/) components
replacing the old Bootstrap controls. [Jotai](https://jotai.org/) manages settings, [TypeScript](https://www.typescriptlang.org/) helps
check the code, and [Vite](https://vite.dev/) and [TanStack Start](https://tanstack.com/start/latest) build the site for static hosting.
D3 still supplies chart utilities, and Timbre still handles synthesis, with native
browser audio decoding replacing the old sample-loading scripts.

The tools have changed, but the idea is the same: a place to experiment, learn,
and make a little music out of sorting.

## Try it or get involved

[Start Sorting](/) or read the [Algorithm API](api.md) to write your own algorithm.
If you find a bug or have a feature request, [open an issue](https://github.com/skratchdot/audio-sort/issues).
56 changes: 56 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Algorithm API

You can add or edit your own JavaScript sorting algorithm from the sorting controls on the [main page](/). Choose **Add Algorithm** to create one, or open the selected algorithm's information dialog to edit its source.

## Writing an algorithm

Enter the **body of a JavaScript function**, without a surrounding `function`
declaration. Audio Sort passes in an object named `AS` that lets your code inspect
the array, compare and swap items, and record sound and visualization markers.
You do not need to return the sorted array.

The algorithm runs first, recording steps for later playback. `AS.play()` records
which items should sound during playback; it does not produce sound immediately.
Use the `AS` comparison and swap methods so those operations appear in the
visualization and counters.

Methods that accept items take either **zero-based array indexes** or item objects
returned by `AS.get(index)`. A number refers to a position, not the value stored
there. For example, `AS.lt(0, 1)` compares the values of the first two items.
An item object keeps referring to the same item even after it moves during a swap.

## Example

Paste this insertion sort into the editor to try it. It compares neighboring
items, records both for playback, and swaps them until they are in order.

```js
for (let i = 1; i < AS.length(); i++) {
let j = i;
while (j > 0 && AS.lt(j, j - 1)) {
AS.play(j, j - 1);
AS.swap(j, j - 1);
j--;
}
}
```

## Reference

| Method | Description | Marker Color | Marker Level |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------ | ------------ |
| **AS.length()** | Returns the number of items in the array. | N/A | N/A |
| **AS.size()** | Alias for AS.length(). | N/A | N/A |
| **AS.get(index)** | Returns a copy of the item at the given index. Pass it to other AS methods to reference that item. Changing the copy does not change the array. | N/A | N/A |
| **AS.play(item1, ..., itemN)** | Records the given items to sound during playback. Accepts indexes or item objects returned by AS.get(). | N/A | N/A |
| **AS.mark(item1, ..., itemN)** | Will mark the given items. Items can be indexes or array items returned via AS.get() calls. | White | 1 |
| **AS.lt(itemOne, itemTwo)** | Returns true if itemOne is less than itemTwo. Item can be an array index, or an array item (returned via an AS.get() call). | Amber | 2 |
| **AS.lte(itemOne, itemTwo)** | Returns true if itemOne is less than or equal to itemTwo. Item can be an array index, or an array item (returned via an AS.get() call). | Amber | 2 |
| **AS.gt(itemOne, itemTwo)** | Returns true if itemOne is greater than itemTwo. Item can be an array index, or an array item (returned via an AS.get() call). | Amber | 2 |
| **AS.gte(itemOne, itemTwo)** | Returns true if itemOne is greater than or equal to itemTwo. Item can be an array index, or an array item (returned via an AS.get() call). | Amber | 2 |
| **AS.eq(itemOne, itemTwo)** | Returns true if itemOne is equal to itemTwo. Item can be an array index, or an array item (returned via an AS.get() call). | Amber | 2 |
| **AS.neq(itemOne, itemTwo)** | Returns true if itemOne is not equal to itemTwo. Item can be an array index, or an array item (returned via an AS.get() call). | Amber | 2 |
| **AS.swap(itemOne, itemTwo)** | Will swap the positions of the two items. | Yellow | 3 |
| N/A | Items that were swapped in the last iteration, will show up below the "swapped" items. They appear as green circles, while items that are getting ready to be swapped show up as yellow circles. | Green | 4 |
| **AS.highlight(item1, ..., itemN)** | Will highlight the given items. Highlighted items stay highlighted until the next AS.highlight() call, or until AS.clearHighlight() is called. | Purple | 5 |
| **AS.clearHighlight()** | Clears the currently highlighted items. | N/A | N/A |
21 changes: 21 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,24 @@ publishing source must be **GitHub Actions**.

- [Architecture](architecture.md)
- [Adding algorithms](adding-algorithms.md)

## Markdown site pages

Edit `docs/about.md` and `docs/api.md` to update the public About and API pages.
The shared `src/components/docs-page.tsx` renderer supports Markdown headings,
lists, links, fenced code, and GitHub-style tables. Raw HTML is not rendered.
Content is included in the static HTML, so it remains readable without JavaScript.

To publish another document:

1. Add a Markdown file in `docs/`, with a single `#` page title.
2. Copy a small route such as `src/routes/about.tsx`, change its route path, and
import your document with Vite's `?raw` suffix. Static routes are prerendered automatically.
3. Add its filename and route to `documentRoutes` in `src/components/docs-page.tsx`
so relative Markdown links such as `api.md` resolve to the published page.
4. Add a link in `src/components/layout/header.tsx` if it belongs in navigation.

Use application paths such as `/` for Home and `api.md` for another published
Markdown document. The renderer uses router links to preserve the `/audio-sort/`
base and client navigation. Use full repository URLs for development documents
that are not published. Adding a file to `docs/` alone does not publish it.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
"lucide-react": "^1.41.0",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"react-markdown": "^10.1.0",
"remark-gfm": "^4.0.1",
"shadcn": "^4.21.0",
"timbre": "^14.11.25",
"tw-animate-css": "^1.4.0"
Expand Down
Loading