Dogalog
livecoding prolog style
Install / Use
/learn @danja/DogalogREADME
Dogalog
Dogalog is a realtime Prolog-based livecoding music environment where you write logic rules to create algorithmic rhythmic patterns and melodies.
Code Live!
Features
- Livecoding: Auto-evaluation with visual feedback - code changes apply automatically
- State Preservation: Cycle counters and cooldowns persist across updates
- Interactive Tutorial: Built-in 13-step guided tutorial for learning
- PWA Support: Install as an app, works offline
- Mobile-First: Touch-friendly UI optimized for all devices
- Modular Architecture: Clean separation of concerns, all files <100 lines
- Comprehensive Testing: 123 tests with 88%+ coverage
Quick Start
npm install
npm run dev
Open the dev server URL, click Tutorial to learn, or click Start and begin livecoding!
What are "rules"?
Rules are Prolog-like statements that define when sounds should play:
% Kick drum on every beat
event(kick, 60, 80, T) :- beat(T, 1).
% Snare on beats 2 and 4
event(snare, 60, 90, T) :- beat(T, 2).
% Hi-hats every 8th note
event(hat, 60, 70, T) :- every(T, 0.5).
The system asks event(Voice, Pitch, Velocity, Time) on every step and plays all matching results.
Builtin Predicates
Timing
beat(T, N)- Trigger on beat N (1 = downbeat, 2 = halfway, 4 = quarter notes)every(T, Step)- Trigger at regular intervals (0.5 = twice per beat)phase(T, N, K)- Trigger on phase K of N divisionseuc(T, K, N, B, R)- Euclidean rhythm (K hits over N steps)
Random & Variation
prob(P)- Succeed with probability P (0.0-1.0)choose(List, X)- Pick random elementcycle(List, X)- Cycle through elements sequentially (stateful!)pick(List, X)- Backtrack through all elementsrand(Min, Max, X)- Random floatrandint(Min, Max, X)- Random integer
Musical
scale(Root, Mode, Degree, Oct, Midi)- Convert scale degree to MIDI notechord(Root, Quality, Oct, Midi)- Generate chord tonestranspose(Note, Offset, Out)- Transpose by semitones
Logic & Control
within(T, Start, End)- Time range check (for song structure)cooldown(Now, Last, Gap)- Prevent rapid retriggeringeq(A, B),lt(A, B),gt(A, B)- Comparisonsdistinct(List)- Check all elements are uniqueadd(A, B, C)- Arithmeticrange(Start, End, Step, X)- Generate number sequencesrotate(List, Shift, OutList)- Rotate lists
Instruments
kick- Synthesized kick drumsnare- Noise-based snarehat- Noise-based hi-hatsine- Sine wave monosynth (use MIDI pitch)
Examples
Euclidean Rhythms
Four-on-the-floor with backbeat:
event(kick, 60, 100, T) :- euc(T, 4, 16, 4, 0).
event(snare, 60, 90, T) :- euc(T, 2, 16, 4, 4).
Complex polyrhythm:
event(kick, 60, 100, T) :- euc(T, 3, 8, 0.5, 0).
event(snare, 60, 80, T) :- euc(T, 5, 8, 0.5, 2).
Melodies with Scales
Pentatonic melody:
note(N) :- cycle([1, 3, 4, 5, 8], D), scale(60, minor_pent, D, 0, N).
event(sine, N, 70, T) :- every(T, 0.5), note(N).
Available modes: major, minor, dorian, phrygian, lydian, mixolydian, locrian, minor_pent, major_pent, blues, whole_tone, chromatic
Arpeggiated Chords
arp(N) :- chord(60, minor, 0, Notes), choose(Notes, N).
event(sine, N, 70, T) :- every(T, 0.25), arp(N).
Chord qualities: maj, min, dim, aug, sus2, sus4, maj7, min7, dom7, dim7
Probability & Variation
Random velocities:
vel(V) :- choose([60, 80, 100], V).
event(hat, 60, V, T) :- every(T, 0.25), vel(V).
Sparse pattern:
event(snare, 60, 80, T) :- beat(T, 2), prob(0.3).
Song Structure with within
% Intro: just kick (beats 0-8)
event(kick, 60, 100, T) :- beat(T, 1).
% Verse: add snare (beats 8-16)
event(snare, 60, 80, T) :- beat(T, 2), within(T, 8, 16).
% Chorus: add melody (beats 16-24)
melody(N) :- scale(60, major, D, 0, N), cycle([1,3,5,8], D).
event(sine, N, 70, T) :- every(T, 0.5), melody(N), within(T, 16, 24).
Fills with cooldown
% Regular pattern
event(kick, 60, 100, T) :- beat(T, 1).
% Fill every 4+ bars
fill(T) :- beat(T, 1), cooldown(T, last_fill, 4).
event(snare, 60, V, T) :- fill(T), every(T, 0.25), choose([80,90,100], V).
Development
Build Commands
npm install # Install dependencies
npm run dev # Start dev server (http://localhost:5173)
npm run build # Build for production
npm run preview # Preview production build
npm test # Run tests
npm run test:ui # Run tests with UI
npm run test:coverage # Generate coverage report
npm run docs:html # Build manual and cheatsheet
Project Structure
src/
├── prolog/ # Prolog engine
│ ├── builtins/ # Builtin predicates (modular)
│ ├── parser.js # Parser
│ ├── resolution.js # SLD resolution with generators
│ ├── tokenizer.js # Tokenizer
│ ├── unify.js # Unification
│ └── terms.js # Term constructors
├── audio/ # WebAudio synthesis
│ └── audioEngine.js
├── scheduler/ # Timing and execution
│ ├── scheduler.js
│ ├── stateManager.js
│ └── transitionManager.js
├── livecoding/ # Auto-evaluation
│ ├── codeValidator.js
│ └── liveEvaluator.js
├── tutorial/ # Tutorial system
│ ├── tutorialManager.js
│ ├── tutorialOverlay.js
│ └── steps.js
├── ui/ # User interface
│ ├── components/ # Reusable components
│ ├── template.js
│ ├── controls.js
│ └── validationIndicator.js
├── help/ # Documentation
│ └── builtinDocs.js
├── config/ # Configuration
│ └── defaults.js
├── app.js # Application orchestrator
└── main.js # Entry point
Architecture
- Prolog Engine: Custom implementation with SLD resolution using ES6 generators for backtracking
- Livecoding: Debounced auto-evaluation (300ms) with syntax validation
- State Management: Centralized state for cycle counters and cooldowns (persists across code updates)
- Scheduler: Time-grid based (16th notes) with swing and lookahead support
- Audio: WebAudio synthesis without samples - all sounds generated in real-time
- UI: Mobile-first, progressive enhancement, DOM-based components
Testing
- 123 tests across 16 test files
- Coverage: 88.52% statements, 90.42% functions
- Integration tests for livecoding, state preservation, example loading
- UI component tests with vitest + jsdom
PWA Features
- Installable on mobile and desktop
- Offline support with service worker
- Caches all assets and documentation
- Manifest with icons and theme colors
Documentation
- Interactive Tutorial: Click "Tutorial" button in the app for 13 guided steps
- Full Tutorial: Comprehensive guide teaching both Prolog and livecoding
- Manual: Complete reference for all built-ins and syntax
- Cheatsheet: Quick reference for common patterns
- Live Demo: GitHub Pages
Technical Details
Livecoding Flow
- User edits code in editor
- After 300ms debounce, code is validated
- If valid: parse → compile → swap program (with smooth transition)
- State (cycles, cooldowns) persists across updates
- Visual indicator shows validation state (green/red/yellow)
State Preservation
% This pattern's state persists when you edit other code:
drums(D) :- cycle([kick, snare, hat], D).
event(D, 60, 80, T) :- beat(T, 1), drums(D).
% Editing this won't reset the cycle counter!
Euclidean Rhythms
Euclidean rhythms distribute K hits as evenly as possible over N steps using the Euclidean algorithm. The result is musically interesting patterns used in music worldwide:
euc(T, 3, 8, 0.5, 0)- Tresillo pattern (Cuban music)euc(T, 5, 8, 0.5, 0)- Cinquillo patterneuc(T, 5, 12, 0.5, 0)- Common rock beat
Browser Support
- Modern browsers with WebAudio API
- Chrome/Edge 90+
- Firefox 88+
- Safari 14.1+
- Mobile browsers (iOS Safari, Chrome Android)
License
MIT
Credits
Built with vanilla JavaScript, CodeMirror 6, and WebAudio API. Inspired by TidalCycles, Sonic Pi, and Datalog.
Related Skills
node-connect
339.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
339.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.9kCommit, push, and open a PR
