Releases: alexnodeland/auracle
Release list
Auracle v0.2.0
The first release under the name Auracle, and the first one that is a
patcher rather than a patchbay with a splice tool behind it. Since 0.1.0 the
instrument gained wiring as a gesture, node identity that survives evolution,
a navigable canvas, destructive verbs you can see and undo, a model that says
what it believes and how sure it is, and an exported picture that is itself a
patch. The prebuilt web bundle is attached below — unzip, python3 serve.py,
play.
Renamed — Ricercar → Auracle
The project is now Auracle (aural + oracle): it listens, it learns, and it
tells you what you are going to like. "Ricercar" was a musician's in-joke that
most people could neither pronounce nor spell.
- Crates
ricercar-*→auracle-*, wasm artifactsauracle_wasm*, worklet
processorauracle-voice, the workspace and every intra-workspace path dep. - The wordmark is
AURACLEwith the final E as the "model is listening"
light — the same one mark, two jobs the final R used to do. - Nothing a player saved is lost, and nothing of theirs is deleted. The
IndexedDB autosave is nowauracle, with an adopt-on-boot chain that reads
ricercarthenevosynth; everyricercar-*/evosynth-*localStorage
preference is copied toauracle-*at import time, before any of it is read,
and never overwrites an answer this build already has. - Exported patches are
.auracle.json, PNGtEXtkeywordauracle, SVG
metadata#auracle-patch. Files exported by any older build still open:
the JSON path never read the marker (a patch is recognized by its shape), and
the PNG and SVG readers try the old names after the new one.
Fixed — a hole that stays a hole, a view that cannot be stranded, and a patcher that fits on a laptop
The rest of the closing gate: the dissenting panelist's two named blockers (M2,
M3), the one-line durability bug the chair pulled in on impact (m1), the two
polish items ruled to ship alongside M2 (p4, p5), and the demo gate (M4).
- An empty socket is named by the node standing in it, not by where that node
sits.placeholderKeyswas a set of trace addresses, so it survived exactly
as long as the addresses did: the client-side rewrite path carried holes
across by object identity and everyStructOp— insert, delete, replace,
set_mod, swap_mix, at any key in the patch — forgot them. Unplug, then insert
anything anywhere, and the dashed EMPTY plate silently became a full vco with
knobs on it. A hole is now keyed byuid, the same identity locks are keyed
by and for the same reason, so it rides through any edit inside the node that
moved. Verified in the browser: an insert that does not touch the hole and an
insert that moves it fromnode/0/1tonode/0/0/1both leave it a hole,
and dropping a source into it clears the mark on the frame the module lands. - A hole survives a reload, in
holeStore/ui.holes, the same shape and
the same argument aslockStore/ui.locks— persisting it is only honest
because it names a node. It also survives ⌘Z/⇧⌘Z, becausebenchStepcarries
it: pruning gets undo right for free and could never have got redo right. case "committed"files the child's locks — and its holes — under the
child. One line and its twin (m1). The commit reply carries nom.subject
so it never reachescase "bench", and IDB ended with an entry for the parent
and none for the patch the player had actually authored: pins evaporating on
reload for the one patch that mattered most, with the next ⚡ then breeding
away the routing they meant to hold. Verified end to end through a commit, a
full page reload, and re-benching the child.- Canvas, bank and accessibility tree agree about absence (p4). The IN THIS
PATCH list printed "vco" and the plate'saria-labelsaid "vco module" about
a socket the canvas was drawing as empty. All three route through one
predicate now; the chip is dashed, reads "empty", and carries no θ, because a
belief about vcos is not a belief about a hole. - The EMPTY plate stops shouting (p5). It was inheriting the plate of
whatever it replaced — up to 240×164 with a recessed control well — giving the
most visual weight on the panel to the thing that is not there. It renders at
the narrow 96-unit width, one row tall, title and hint only, no well. - Freeform can no longer strand the view, and now says so if it has.
contentBox()returns the modules' bounding box instead of the layout
canvas's extent, so a fit is a fit of what is drawn — a persisted layout that
put every plate at y ≈ 3400 had Home dutifully framing 3744 units of which
3400 were empty. The minimap reads the same box.applyGridre-seeds from the
chain when what is drawn is degenerate, instead of pinning the stranding —
the one command that looked like a rescue was the one that made the damage
permanent. A stored layout that places under two thirds of the rack's nodes is
dropped wholesale rather than applied, and the inheritance test rose from
"some uid in common" (1 in 18) to the same floor. A reset verb sits in
the freeform controls, and below 0.30× with a measurably worse-than-chain
arrangement the frame itself offers it. Measured on a reproduced stranding:
0.049× → 0.249× at 1280×900, 0.080× → 0.403× at 1700×1000. - The patcher fits on a laptop (M4). The docked spec card collapses to a
single line when it has nothing to describe (and stays one line while armed,
so a placement in progress never resizes the canvas underneath itself); the
short-laptop media query's breakpoint moves from 860px to 940px, which is
where it was always meant to apply — 1280×900 is the plan's own second test
size; a draggable divider above the strip gives the player the final say,
the node bank's rail pattern on the other axis, persisted and keyboard-
operable; and the auto-LOD threshold scales with the frame's height, because
what makes a knob small in a 364px band is the band, not the patch. Result at
1280×900: rack frame 295 → 364px, and 5 of 5 stock presets open in
full detail with knobs (First Bass 0.67, Sub & Sparkle 0.61, Acid Line 0.67,
Reese 0.44, Anvil 0.67 against a 0.40 threshold) where 5 of 5 opened as
knob-less block diagrams. At 1700×1000 the frame is 489px, the threshold 0.54,
and all five are in full detail. - The freeform verbs hold their slots (m6, taken because M3 would otherwise
have made it worse).apply gridused to bedisplay: noneoutside freeform,
so entering the mode slid the layout toggle ~100px under the pointer that had
just pressed it and a second press fired apply grid — a command that
rewrites every position. Both verbs are now reserved and disabled, and both
are one word (snap,reset), because two long labels wrapped the group onto
a second row at 1280 and cost 35px of the very budget M4 is fighting for.
Fixed — the sentinel: a knob outside its range, and everything downstream that believed it
The closing panel's one non-negotiable item, found independently by three
reviewers from three unrelated surfaces: a faceplate reading "SUSTAIN 1200.0
dB", a HELD fragment printing 1e+30 for every parameter, and six cells of
exactly 1e30 inside the raw φ of the persisted observation log.
- Every continuous site in the grammar has a declared range, and it is now
written down —PARAM_DOMAIN, one constant, next to theu01()the prior
actually samples from.PatchTree::domain_violationsreports the sites that
leave it andPatchTree::clamp_domainspulls them back, both by walking the
trace rather than matching 26 productions: the trace enumerates exactly
the continuous sites, by construction, so there is no second table of "which
fields are knobs" for the next module to be left out of. validate_tree— the WS-1 rider — now speaks about values. It has always
gated size, depth and modulation depth; it had nothing to say about a knob,
which is why a value could walk through it intoedit_set_tree, into
finish(), into φ, into the exported PNG'stEXtchunk and into the log.- Domains are repaired, ceilings are refused, and the asymmetry is the
point: a 40-node patch cannot be clamped without deciding what to delete, and
a knob can be fixed exactly. Refusing would have meant a saved session that
already contains one becomes an app the player cannot edit their way out of.
finish()(so everyReplaceTree/InsertTree/SetModTreefragment the
panel hands in),edit_set_tree_apply,import_patchand the refinement
boundary all repair; identities survive, so locks and hand-placed positions
ride through the repair. - The featurizer's quarantine caught only audio pathology.
sustain = 1e30
renders fine — the limiter bounds the voice — so it passed the vet and its φ
became evidence.featurizenow refuses an out-of-domain term before the
render, and refuses a non-finite coordinate after it. Standardizer::fitgained a runaway-column detector — and it is a detector,
not a trim, because the trim was measured and thrown out. One escaped row
gaveamp_sustaina mean of ~1.2e29 and a σ of ~5.5e29, which standardizes
every real patch to the same place: a dead coordinate the model can never
learn from while the belief line still prints a contribution for it. The first
fix was routine winsorization at 2% per tail; the 16-seed paired run took it
straight back out (+1.877 ± 0.362→+0.204 ± 1.347mean gain, 15/16 → 11/16
seeds climbing, one seed at −18.2). Trimming a real tail is not free. So the
shipped rule uses the plain moments unless a column's plain σ exceeds its
winsorized σ by more thanRUNAWAY_RATIO, which makes it a bit-identical no-op
on clean data by construction rather than by luck. The threshold was measured
too — a newwinsor_ratioexample fits 150 clean 48-patch ...
Ricercar v0.1.0
What's Changed
- release: v0.1.0 machinery — tag-triggered web-bundle releases by @alexnodeland in #1
New Contributors
- @alexnodeland made their first contribution in #1
Full Changelog: https://github.com/alexnodeland/ricercar/commits/v0.1.0