neuron-explorer
Qwen3.5‑4B 전용 조향형 뉴런 탐색기, 모든 MLP 뉴런을 밀어 결과를 보관·탐색
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A browser-based live coding instrument where music is written in a small, purpose-built Lisp.
Think Strudel, but the user-facing language is a minimal Lisp and the
pattern engine is implemented in ClojureScript.
The name: REPL + pulse (rhythm, heartbeat).
I love Clojure — its REPL-driven workflow, immutable data model, and the way it makes you think
about time and transformation. REPuLse is what happens when that mindset meets live music: a
sequencer you talk to like a Clojure REPL, where patterns are pure functions and the output is
sound.README 전문 보기 ↗A browser-based live coding instrument where music is written in a small, purpose-built Lisp. Think Strudel, but the user-facing language is a minimal Lisp and the pattern engine is implemented in ClojureScript.
The name: REPL + pulse (rhythm, heartbeat).
I love Clojure — its REPL-driven workflow, immutable data model, and the way it makes you think about time and transformation. REPuLse is what happens when that mindset meets live music: a sequencer you talk to like a Clojure REPL, where patterns are pure functions and the output is sound.
REPuLse is a pattern-based live coding instrument. Patterns describe what sounds play and when — not how synthesis works internally.
REPuLse is NOT a signal-flow language like SuperCollider, Overtone, or Extempore. There is no manual oscillator routing, no inline filter chaining, no bus/send architecture at the pattern level.
:bd, :sd), note keywords (:c4), Hz numbers (440), or (synth :saw) / (synth :fm :index 4)seq, stack, fast, slow, every, cat, euclideanamp, decay, attack, pan, synth — applied via ->> (thread-last)(fx :reverb 0.4), (fx :delay :wet 0.3 :time 0.25), (fx :cab :ir :4x12) — not inline filter graphsdefsynth, which defines reusable instruments from UGen primitives — this is a separate layer from pattern code(bpm 130)
(def kick (seq :bd :_ :bd :_))
(def snare (seq :_ :sd :_ :sd))
(def hats (fast 2 (seq :hh :_)))
(def bass (->> (scale :minor :c2 (seq 1 :_ 5 :_))
(synth :saw)
(amp 0.5) (decay 0.3)))
(stack kick snare hats bass)
See docs/USAGE.md for the full language reference.
Requirements: Node.js 18+, Java 11+ (for shadow-cljs), Rust + wasm-pack (for WASM synthesis)
git clone <repo>
cd repulse
npm install
# Build the Rust/WASM synthesis engine (first time only)
npm run build:wasm
# Start the dev server
npx shadow-cljs watch app
Open http://localhost:3000.
You should see a dark editor. Type this and press Alt+Enter (or Option+Enter on macOS):
(seq :bd :sd :bd :sd)
You'll hear a kick and snare alternating in a loop. To stop:
(stop)
If you skip
npm run build:wasm, the app still works — it falls back to a JS synthesis engine automatically. You'll see[REPuLse] audio backend: clojurescript synthesisin the browser console.
npm test # ClojureScript unit/integration tests
npm run test:rust # Rust AudioEngine tests
npm run test:e2e # Playwright browser offline audio tests
npm run test:all # full local verification suite
./scripts/test-all.sh # same full suite
The browser audio tests use a dedicated test harness with OfflineAudioContext
and report the "offline-js" backend. They verify the offline render/export-style
path. Production browser AudioWorklet + WASM PCM capture is tracked separately
in Phase TEST2.
See docs/TESTPLAN.md for the coverage map.
REPuLse-Lisp is a minimal Lisp DSL wrapped around a pattern algebra. A pattern is a pure function from a time span to a list of events — the same model used by TidalCycles and Strudel.
| Expression | Description |
|---|---|
(seq :bd :sd :hh) | Sequence values evenly across one cycle |
(stack p1 p2) | Layer two patterns simultaneously |
(pure :bd) | One value repeated every cycle |
(fast 2 pat) | Double the speed |
(slow 2 pat) | Halve the speed |
(rev pat) | Reverse a pattern within each cycle |
(every 4 (fast 2) pat) | Apply transform every 4th cycle |
(fmap f pat) | Apply a function to every event value |
(scale :minor :c4 pat) | Map degree integers in pat to Hz using a named scale |
(chord :major7 :c4) | Stack chord tones as a pattern of Hz values |
(transpose 7 pat) | Shift all Hz values by n semitones (keywords pass through) |
(->> pat (amp 0.8) (attack 0.02)) | Thread pattern through parameter transformers |
(amp 0.8 pat) | Set amplitude 0.0–1.0; (amp 0.8) returns a transformer |
(attack 0.05 pat) | Envelope attack time in seconds |
(decay 0.4 pat) | Envelope decay time in seconds |
(release 0.5 pat) | Envelope release time in seconds |
(pan -0.5 pat) | Stereo panning -1.0 (left) to 1.0 (right) |
(comp f g …) | Compose transformers right-to-left: (def pluck (comp (amp 0.8) (decay 0.15))) |
(~ "bd sd [hh hh] bd") | Mini-notation: compact string syntax for patterns (see below) |
(alt p1 p2 p3) | Alternation: cycle 0 plays p1, cycle 1 plays p2, etc. |
(load-gist url) | Load a GitHub Gist into the editor and auto-evaluate |
(export 4) | Render 4 cycles to a downloadable WAV file |
| Value | Sound |
|---|---|
:bd | Kick drum |
:sd | Snare |
:hh | Closed hi-hat |
:oh | Open hi-hat |
:_ | Rest (silence) |
440 | Sine tone at that frequency in Hz |
:c4, :eb3, :fs5 | Note keyword — sine tone at that pitch (s=sharp, b=flat) |
(sound :bank n) | Sample from the Strudel CDN library by name and index |
| any loaded keyword | Plays the matching sample bank (e.g. :cp, :bass, :tabla) |
Over 100 sample banks from the Strudel CDN (TidalCycles Dirt-Samples +
Tidal Drum Machines) are loaded at startup. Use (sound :bd 2) for indexed access.
; Four-on-the-floor kick with snare on 2 and 4
(stack (seq :bd :bd :bd :bd)
(seq :_ :sd :_ :sd))
; Hi-hats twice as fast as the kick
(stack (seq :bd :_ :bd :_)
(fast 2 (seq :hh :_)))
; Open hi-hat on the offbeat
(stack (seq :bd :_ :bd :_)
(seq :_ :oh :_ :oh))
; Every 4th cycle, double the speed
(every 4 (fast 2) (seq :bd :sd :bd :sd))
; Define and reuse patterns
(def kick (seq :bd :_ :bd :_))
(def snare (seq :_ :sd :_ :sd))
(stack kick snare)
; Tone sequence
(seq 220 330 440 550)
; Samples from the library
(seq (sound :tabla 0) (sound :tabla 1) :_ :_)
; Effect chain — reverb and filtered delay
(do
(fx :reverb 0.3)
(fx :delay :wet 0.4 :time 0.25 :feedback 0.4)
(fx :filter 3000)
(seq :bd :sd :bd :sd))
; Local bindings
(let [n 4
pat (seq :bd :sd)]
(fast n pat))
; Anonymous functions
(fmap (fn [x] (if (= x :bd) 80 440)) (seq :bd :sd))
; Arithmetic
(fast (+ 1 1) (seq :bd :sd))
~ parses a compact string into a pattern, composing with all other functions:
| Syntax | Example | Meaning |
|---|---|---|
| space-separated | "bd sd hh" | sequence of 3 equal slots |
[…] | "bd [sd hh]" | subdivision — contents share one parent slot |
*N | "hh*4" | repeat N times |
<…> | "<bd sd cp>" | alternation — cycle N picks element mod N |
~ or _ | "bd ~ sd" | rest / silence (:_) |
? | "bd?" | 50% probability of playing |
:N | "bd:2" | sample index ({:bank :bd :n 2}) |
@N | "bd@3 sd" | weight — bd takes 3 units, sd takes 1 |
| bare number | "440" | numeric value |
| note name | "c4 eb3" | keyword (:c4, :eb3) |
(~ "bd [sd hh] bd sd") ; subdivision
(->> (~ "c4 e4 g4") (amp 0.6) (attack 0.02)) ; with params
(fast 2 (~ "bd sd")) ; with transformers
(stack (~ "bd _ bd _") (~ "_ sd _ sd")) ; stacked
repulse/
├── packages/
│ ├── core/ # Pattern algebra — pure CLJS, no DOM, no audio
│ │ └── src/repulse/core.cljs
│ ├── lisp/ # REPuLse-Lisp reader + evaluator
│ │ └── src/repulse/lisp/
│ │ ├── reader.cljs # Recursive-descent parser
│ │ ├── eval.cljs # Environment-based evaluator
│ │ └── core.cljs # Public eval-string entry point
│ └── audio/ # Rust/WASM synthesis engine
│ ├── Cargo.toml
│ └── src/lib.rs # Kick, snare, hi-hat, tone via web-sys
├── app/ # Browser app
│ ├── src/repulse/
│ │ ├── app.cljs # UI bootstrap + CodeMirror 6 editor
│ │ ├── audio.cljs # Web Audio scheduler + WASM integration
│ │ ├── samples.cljs # Sample loader (CDN + external manifests + GitHub)
│ │ ├── plugins.cljs # Plugin registry
│ │ ├── fx.cljs # Effect chain manager
│ │ ├── plugins/
│ │ │ └── compressor.cljs # Dynamics compressor (CLJS implementation)
│ │ └── lisp-lang/ # CodeMirror 6 language extension
│ │ ├── repulse-lisp.grammar # Lezer grammar source
│ │ ├── parser.js # Generated parser (committed)
│ │ ├── highlight.js # Syntax highlight tag mapping
│ │ ├── rainbow.js # Rainbow delimiter ViewPlugin
│ │ └── index.js # LanguageSupport export
│ └── public/
│ ├── plugins/
│ │ ├── oscilloscope.js # Built-in oscilloscope visual plugin
│ │ ├── reverb.js # Convolution reverb effect
│ │ ├── delay.js # Tape delay effect
│ │ ├── filter.js # Biquad filter effect
│ │ ├── dattorro-reverb.js # Dattorro plate reverb (AudioWorklet)
│ │ └── cab.js # Speaker cabinet convolution effect
│ ├── worklets/
│ │ └── dattorro-reverb-processor.js # AudioWorkletProcessor
│ └── … # Static assets + compiled JS output
├── package.json # npm workspaces root
└── shadow-cljs.edn # Build config
# Build Rust/WASM engine (required once, or after changing packages/audio/src/lib.rs)
npm run build:wasm
# Start dev server with hot reload at http://localhost:3000
npx shadow-cljs watch app
# Both in one step
npm run dev:full
# Run core unit tests (Node.js)
npx shadow-cljs compile test && node out/test.js
packages/core — pure pattern algebra. A Pattern is a map {:query fn} where the
function takes a {:start r :end r} span (rational numbers as [n d] vectors) and returns
a sequence of events. Zero dependencies beyond cljs.core.
packages/lisp — a hand-written recursive-descent reader and an environment-based
evaluator. The initial environment is populated with all core functions. Undefined symbol
errors include Levenshtein-based typo hints.
packages/audio — a Rust crate compiled to WASM via wasm-pack. Provides an
AudioEngine class with a trigger(value, time) method. All synthesis (kick, snare,
hi-hats, tones) uses Web Audio API nodes via web-sys. Noise buffers are generated with
a deterministic LCG — no Math.random(). Loaded as a <script type="module"> in
index.html to bypass Closure Compiler's lack of import.meta support.
app/audio.cljs — implements the Web Audio lookahead clock
pattern (Chris Wilson). A setInterval fires every 25 ms and schedules any events falling
within the next 200 ms lookahead window using AudioContext.currentTime. Sound dispatch:
sample bank → WASM synth → JS synth fallback.
app/samples.cljs — fetches two JSON manifests from the Strudel CDN at startup and
builds a lazy buffer cache. Buffers are decoded on first use and reused thereafter.
app/plugins.cljs — a plugin registry with protocol validation. Plugins are ES
module default exports — either a plain object or a class extending VisualPlugin /
EffectPlugin from app/public/plugin-base.js. The built-in oscilloscope auto-loads
at startup. Load third-party plugins at runtime: (load-plugin "https://…/plugin.js").
The AnalyserNode on the master bus feeds visual plugins.
See docs/PLUGINS.md for the full plugin development guide.
— mounts a CodeMirror 6 main editor and a single-line command bar editor; wires to and routes Pattern results to the audio scheduler vs. plain values to the output line. A live context panel shows BPM, user bindings, and the active effect chain; a track visualizer panel below the editor shows all active tracks with canvas modes that reuse cached per-cycle energy curves during drawing. All panels update reactively via on the relevant atoms.
| Key | Action |
|---|---|
| Alt+Enter / Option+Enter | Evaluate buffer (global — works even when editor is not focused) |
| Ctrl+. or F9 | Run (upd) — apply BPM/param changes without restarting patterns (global) |
| Escape | Focus command bar |
| Ctrl+A / Cmd+A | Select all code (global — works even when editor is not focused) |
| Ctrl+Z / Cmd+Z | Undo |
| Ctrl+Shift+Z / Cmd+Shift+Z | Redo |
Below the editor is a single-line command bar (bash-style REPL) for imperative
commands that shouldn't live in the buffer — mute!, unmute!, solo!, clear!,
tap!, tracks, upd, etc.
| Key | Action |
|---|---|
| Enter | Evaluate and clear |
| Escape | Clear and return focus to editor |
The command bar has full syntax highlighting and autocompletion (same as the main editor),
but its content is not saved to localStorage.
Pattern built-ins (pure functions, no DOM or audio):
make-env in packages/lisp/src/repulse/lisp/eval.cljsAudio/UI built-ins (touch audio, DOM, or network — e.g. fx, load-plugin, samples!):
Add directly to the assoc in ensure-env! inside app/src/repulse/app.cljs
Syntax highlighting + autocompletion for any new built-in:
The Lezer grammar controls which names are coloured as built-ins in the editor. The compiled parser is committed to the repo — edit the source, then regenerate:
BuiltinName in
app/src/repulse/lisp-lang/repulse-lisp.grammarnpm run gen:grammar — this overwrites parser.js and parser.terms.jsdetail docstring) to
app/src/repulse/lisp-lang/completions.jsThe generated parser.js must be committed alongside the grammar source.
Open packages/audio/src/lib.rs and add a match arm to trigger(),
then implement a play_* method on AudioEngine. Run npm run build:wasm to rebuild.
REPuLse is open to contributions! Here's how you can help:
Open a GitHub issue describing a function, pattern combinator, or capability you'd like to see. Browse the ROADMAP.md for planned phases and existing ideas.
The PROMPTS/ folder contains detailed specs for upcoming features. Pick one that interests you:
maincore functions (see packages/core/src/repulse/core_test.cljs)mainSee the Development setup section above to get your local environment running.
Found something broken? Open an issue with steps to reproduce — include the code you typed in the editor and what you expected to hear.
Works on Chrome, Firefox, and Safari. Safari requires the webkitAudioContext fallback and
an unconditional .resume() call — both handled automatically.
(arrange [[p 4] [q 8]]) | Play sections in order for N cycles each, then loop |
(play-scenes [p q r]) | Play each pattern for 1 cycle in sequence, then loop |
(bpm 140) | Set the tempo in BPM (default: 120) |
(fx :reverb 0.4) | Set reverb wet mix (built-in convolution reverb) |
(fx :dattorro-reverb 0.5) | Dattorro plate reverb (AudioWorklet, high quality) |
(fx :delay :wet 0.4 :time 0.25) | Tape delay with feedback |
(fx :filter 800) | Lowpass filter cutoff in Hz |
(fx :compressor :threshold -18) | Dynamics compressor |
(fx :cab :ir :4x12) | Speaker cabinet simulation |
(fx :off :reverb) | Bypass an effect (transparent) |
(fx :on :reverb) | Re-enable a bypassed effect |
(track :name pattern) | Define or replace a named track — use in the editor buffer |
(mute! :name) | Silence a track without removing it — use in the command bar |
(unmute! :name) | Re-enable a muted track — use in the command bar |
(solo! :name) | Play only this track, mute all others — use in the command bar |
(clear! :name) | Remove a named track — use in the command bar |
(clear!) | Remove all tracks and stop — use in the command bar |
(tracks) | Return list of active track names |
(upd) | Hot-swap: re-evaluate the editor buffer and update running tracks without stopping — use in the command bar |
(tap!) | Register a BPM tap; 4 taps sets tempo (or click the tap button) |
(midi-sync! true) | Enable MIDI clock sync from external hardware |
(midi-map :cc 1 :filter) | Map MIDI CC #1 to master filter cutoff (also :amp, :bpm) |
(midi-out 1 pat) | Route pattern events as MIDI Note On/Off on channel 1–16 |
(midi-clock-out! true) | Broadcast 24ppqn MIDI clock at current BPM |
(midi-export :track 4) | Export 4 cycles of a track as a .mid file |
(freesound-key! "key") | Set your Freesound API key (get one at freesound.org) |
(freesound! "kick 808") | Search Freesound and load samples as :freesound-<id> |
(samples! "github:owner/repo") | Load sample banks from a public GitHub repo (auto-discovers audio files) |
(samples! "https://…/samples.edn") | Load banks from a REPuLse Lisp manifest |
(samples! "https://…/samples.json") | Load banks from a Strudel-compatible JSON manifest |
(sample-banks) | List all currently registered sample bank names |
(load-plugin url) | Load a visual or effect plugin from a URL |
(stop) | Stop playback |
(demo :techno) | Load and play a starter template (:techno, :ambient, :dnb, :minimal, :house, :dub, :experimental) |
(demo) | List all available demo templates |
(tutorial) | Load tutorial chapter 1 into the editor (does not auto-play) |
(tutorial 3) | Load tutorial chapter 3 (chapters 1–8) |
app/app.cljseval-stringdefrequestAnimationFrameadd-watch