Merge pull request #12 from knonode/main
much update many wow
97d51dd5
main
106/14,191 ++ 25,285 --
Commits and releases over time
No repositories match that filter.
much update many wow
It inherited the cyan the old viz buttons used, which is harder to read at eleven pixels than the white on the buttons beside it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3U3qYRnw6NPt5BRj81S9X
Eight buttons across the left of the second row, only ever one of them in use. They were the widest thing in the bar and pushed everything else onto a second line at any ordinary window size. The bar is one row again at 1100 pixels. The three unbuilt ones keep their slots and their order in the menu, greyed out, because the order is the roadmap and not an accident of when each was written. The menu's own name is the "none" entry, so picking Visualize again closes what is open, alongside Escape and a click on the overlay itself. Escape and the click reset the menu, or it would go on naming a visualization that had already gone. The guide loses its screenshot for this section: the set is in a dropdown now, and a closed dropdown shows none of it. The text names the menu instead, and the capture run drops the stale PNG on its own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3U3qYRnw6NPt5BRj81S9X
Three lines of height off the card, and a label that stops throwing my prose at you. "round trip" was a phrase, not a reading. It is lat. now, next to bal., and the two share one line: at a card's width they fit even at the worst case of a four-digit latency, measured down to a 241px card with four to a row. The tooltip spells both out, along with the escrow address. The resolved address under Play as answered "which account did that name mean" once and then charged for the answer forever. It clears itself after four seconds, and the row collapses rather than sitting empty. A failed lookup stays, because it is still true. Play as had a sixty-pixel label column to line up with rows that no longer exist — device and channel left for the header. The label takes the width of its own text now, so the input keeps what it gains as the card narrows. Card height: 893 to 865. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3U3qYRnw6NPt5BRj81S9X
Two problems, one of which had no answer at all. Nothing anywhere told you where to send money. The card showed a balance draining and no way to fill it — you would have had to read the TEAL to find the address. The balance line now carries it in its tooltip and copies it on a click, which costs no height, because a line that says "escrow: 0.141 ALGO" is already the line about the escrow. Device and channel were two rows in the parameter area. They are now two dropdowns in the header, where Type and Sub sit on every other card and where the room already existed. The MIDI card is the same height as an ordinary synth card again: 892 pixels against 892, measured rather than assumed. The device picker reads MIDI until a device is chosen, so the header still names the card. Device names are longer than the select is wide; the tooltip carries the full one. The guide follows both: where the pickers are, and that clicking the balance copies the address to top it up. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3U3qYRnw6NPt5BRj81S9X
Nothing in this takes a keyboard. It takes note-on with velocity, which is what pads, MPCs, wind controllers, guitar pickups, sequencers and anything with a MIDI out send. The copy said keyboard throughout because the first device to play it was one. It read worst in the 0.11.0 note — "one keyboard can send up to eight parts" excludes exactly the multi-track devices that feature exists for. Two uses of the word are left. One is the computer keyboard that reorders cards, which is what it says. The other is the list of examples in the guide, where a keyboard is one of the things named. Copy only, so no version bump: a card that read the release notes once is not worth interrupting again over a wording fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3U3qYRnw6NPt5BRj81S9X
The guide gains a Channel paragraph in the MIDI section: leave it on all for one keyboard, add a card per track and set a channel each for a device that sends several at once. The release notes lead with the part that needs saying loudest, which is that everyone has to update. Notes on channels 2 to 8 are dropped by 0.10.0 rather than sounding wrong, so a friend still on the old build hears a quarter of a four-track performance and no error. MINOR: a 0.10.0 preset still loads, and channel is a new key with a default. The break is in what goes over the network, not in what a preset means, and the compatibility surface here is presets. The MIDI card screenshot is recaptured for the new row. The other twenty-one are left alone — a full run rewrites them all, but only this one changed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3U3qYRnw6NPt5BRj81S9X
Rewritten in your voice, plus four typos. A tab had got into "Plug in your MIDI keyboard", and "plug in ... into" doubled the preposition. "Through relay node" wanted an article. In the guide, the Play as paragraph had lost the clause between "an NFD name.algo" and "Leave it empty", which left a semicolon in front of a capital letter. The paragraph after it kept a dash that no longer had anything on the other side of it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3U3qYRnw6NPt5BRj81S9X
A groovebox is not a keyboard. Its tracks are separate instruments, and arriving as one merged stream in one voice is the wrong answer to what the device is for. The separation could have come from addresses — a different "Play as" per track, four tracks arriving as four strangers. That works today with no change at all, and it is wrong. Identity is load-bearing here: it carries your NFD, and it is what "hear only this player" asks about. Four tracks of one performance are not four people, and answering a filter for one of them with a quarter of the music is a bug wearing a feature's clothes. So the part rides in the asset ID, next to the pitch. Each note has always owned a thousand IDs and a keypress only ever needed a velocity, so nine tenths of every slot was empty: it now holds eight parts of a hundred steps each. The top two hundred stay unreachable from a keyboard, which is where the voice announcement already lives. Nothing about the escrow changes — the range check still holds, with two hundred to spare at the top — so the instrument keeps its address. Velocity drops from 128 levels to 100. It was only ever read as a gain between 0.05 and 1, so the loss is arithmetic rather than audible. This is a change to what goes on the wire. A listener on 0.10.0 will hear part 0 and silently drop the rest, since their decoder rejects a velocity above 127 — which is the correct behaviour for them and a reason for this to go out as a release rather than sit on a branch. The rest follows from the encoding. Voices are filed under player and part rather than player alone, so one performer's tracks stop overwriting each other's sound. A card knows which part it plays, so the card that sent a note is the one that sounds it, instead of all four playing every line. And a device now feeds as many cards as want it, each on its own channel — binding was one-at-a-time before, on the reasoning that two cards on one keyboard would pay twice for every keypress. They would not: they listen on different channels, and a keypress only lands on one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3U3qYRnw6NPt5BRj81S9X
The escrow readout says what the hat holds, which is everyone's. It does not say what you have spent, and those are different questions the moment more than one person is playing. They are different for a second reason, which is the one that prompted this. An arpeggiator bills you a note at a time without a finger moving, and a sequencer left running does it indefinitely — the first you would otherwise know of either is an empty hat. The count is worth its line on the card while it is happening rather than afterwards. Notes dropped by the rate cap get a line too. They cost nothing, but you pressed a key and heard silence, and that is worth saying rather than leaving you to wonder whether it went out. The readout is four short lines now instead of two long ones. A card is about twenty-eight characters wide at this size, so a line carrying two facts wraps mid-phrase and reads as neither. window.SOA_MIDI.spend() gives the same numbers from the console, next to voices() and playing(). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3U3qYRnw6NPt5BRj81S9X
The escrow balance was read once when the card was built and never again, so the one number that tells you how much playing is left sat still while you spent it. A reload was the only way to find out. It is now driven by what is heard rather than by asking. Every note is a transaction that passes this browser on its way back from the relay, and every one of them costs the same minimum fee, so a keypress anywhere in the world moves the number here at the moment you hear the note that spent it. That covers other people's playing too, which is the point: the hat is shared, and watching it drain is part of knowing whether to top it up. Counting what you hear drifts — the stream can be stopped, a relay can miss a transaction, and someone who is not playing can top the hat up — so the count is corrected against the chain every forty-five seconds, and not at all while the tab is hidden, since nobody is watching a number they cannot see. A failed read is left alone rather than treated as a balance of nothing. The probe's floor drops from 0.2 ALGO to 0.05. The old figure was picked out of the air and refused to play a hat that could still afford a hundred and sixty notes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3U3qYRnw6NPt5BRj81S9X
The guide gains a last section, after presets, because the keyboard is the one part of this app that does not listen. It says what a note actually is, that you will not hear a key when you press it, that the instrument belongs to nobody, and what Play as buys you — which is not identity for its own sake but the thing that lets your sound travel with your notes. The second row's section gains the two controls beside + MIDI. Others is described where the reader meets it rather than in the MIDI section, since it governs what you hear whether or not you ever plug a keyboard in. MINOR by the rule in the README: settings keys were added with sensible defaults and nothing was renamed or repurposed, so a preset written by 0.9.0 sounds the same here. Only two screenshots are committed. A full capture run rewrites all twenty-two, but the other twenty differ only in font rendering — this machine's Chromium against whoever captured them last — and the presets modal cannot have been changed by any of this work. Committing them would be twenty binary files of noise around the two that mean something. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3U3qYRnw6NPt5BRj81S9X
A note is a transaction: a zero-amount transfer of an asset that does not exist. The AVM allows this because a zero transfer returns before it looks up any holding, so no opt-in is needed, no supply is needed, and the asset ID is free to mean something other than an asset. It means the note — 2^40 + midiNote*1000 + velocity, three orders of magnitude above the highest real asset ID so it can never be mistaken for a transfer of something that exists. The amount cannot carry anything, which is the one thing that had to be designed around rather than chosen. A non-zero transfer needs a holding the sender does not have, so every note is aamt 0 and the pitch lives somewhere else. Sending to yourself is out for the same family of reasons: aamt 0 to your own address is the opt-in branch, which does look the asset up and fails. The instrument is an escrow with no private key. tools/midi/keyboard.teal authorises exactly one shape of transaction — axfer, amount zero, fee at most the minimum, no clawback, no close-out, no rekey, asset ID inside the note range — so the only thing that can ever leave the account is fees. Anyone holding the program can sign for it, which is the point: several people play the same instrument at once with no server, no session and nothing to coordinate, because Algorand has no nonces and simultaneous senders never collide. The receiver field carries who played, since the sender is the escrow for everybody. It costs nothing, a zero transfer never touching the receiving account, and it can be typed as an NFD. Nothing is heard when it is sent. A note is heard when it comes back through the relay, most of a second later, in whatever order gossip chose. That is not a defect to be papered over: the mempool is the delay line, and the instrument is one whose latency is a live measurement of the network. Slow, sparse, chordal playing sounds deliberate. Fast runs sound like a fax machine, and should. A player's sound travels with them, in the note field of the notes they are already sending. A fully designed voice serialises to about 460 bytes against the 1024 a note field allows, and mainnet's fee-per-byte is zero, so those bytes are free space rather than a cost — every note carries the whole sound, a change is heard on the very next keypress, and someone who joins mid-jam has your voice on the first note they hear. No transaction is ever sent for a voice alone. That voice is a stranger's data applied to your audio graph, so services/midi/voice.ts forces every value into a range Tone can take before it reaches a node, refuses a payload from a format version it does not know rather than voicing it with today's reader, and drops the fields that are a card's state rather than a sound. It cannot mute your synth or move your sequencer. It also cannot move the shared reverb, which belongs to everybody's hall rather than one player's patch. Applying a voice is cheap in the case that matters. Only the engine is a different class of object; waveform, envelope, detune, cutoff, delay, pan and LFO are parameters on nodes that already exist, so applyVoice sets them on a running graph and rebuilds only on an engine change. Since every note carries its player's whole sound, a fingerprint comparison on the way in means Tone is touched only when the sound actually differs — on a knob turn, never on a keypress. Nothing needs rate limiting. Four voices, evicted least-recently-heard, kept out of activeSynths on purpose: they are not cards, and must never be saved into a preset, reordered, or matched against ordinary transaction rules. Your own notes go to your own card, where the sound you are designing lives and where the LED tells you the mempool heard you. Everyone else goes to the pool. A card never plays another player's notes — hearing four people through one card's voice was only ever a stand-in for not having their voices. Anonymous players, having no address to file a sound under, share one slot and the house default rather than being silent. Two things had to be learned by encoding a transaction and reading the bytes back, because neither is visible in this code. Canonical msgpack omits zero-valued fields. So aamt is absent rather than 0 on every note, and arcv is absent entirely when the receiver is the zero address. Both guards are written around that. And gossip dedup was dropping notes. A logic-signed transaction has no sig, so the fallback key was a composite of type, sender, fee and validity window — every one of which is identical for every note this escrow plays in a given minute. The first note of each window would have sounded and the rest would have been swallowed in the ingest layer, before any synth saw them. The key is now built at normalize time, while the raw bytes are still in hand, from what actually differs: the asset ID that carries the note, the receiver that says who played it, and a hash of the bytes the sender added to keep two identical notes from being one transaction. This was never MIDI-specific; all lsig and msig traffic was under-deduplicated the same way, and MIDI only made it total. One bug is left alone deliberately. axfer-opt-in tests (aamt ?? -1) === 0 against a field msgpack drops, so that subtype has never matched anything. Fixing it changes what an existing preset hears, which is a release decision rather than a drive-by. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3U3qYRnw6NPt5BRj81S9X