• Stars
    star
    124
  • Rank 288,207 (Top 6 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 8 years ago
  • Updated over 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Create observables and map them to DOM elements. Massively inspired by hyperscript and observ-*, but avoids GC thrashing.

mutant

Create observables and map them to DOM elements. Massively inspired by hyperscript and observ-*.

No virtual DOM, just direct observable bindings. Unnecessary garbage collection is avoided by using mutable objects instead of blasting immutable junk all over the place.

Current Status: Experimental / Maintained

Expect breaking changes.

Used By

  • Loop Drop: Live electronic music performance app. MIDI looper, modular synth and sampler app built around Novation Launchpad controller. Powered by Web Audio, Web MIDI, and electron.
  • Patchwork: A decentralized messaging and sharing app built on top of Secure Scuttlebutt (SSB).
  • Ferment: Peer-to-peer audio publishing and streaming application. Like SoundCloud but decentralized. A mashup of ssb, webtorrent and electron.

Install

npm install mutant --save

Compatibility

Requires an environment that supports:

  • setImmediate(fn) (only available in node/electron by default so in browser need to use setImmediate shim)
  • requestIdleCallback(fn) (optional, only when using {idle: true}, mutant/once-idle or mutant/idle-proxy)
  • Map, WeakMap, and WeakSet
  • element.classList
  • MutationObserver (optional, only for root html-element binding support)
  • ES5 arrays (Array.prototype.forEach, etc)
  • IntersectionObserver (optional, only when using intersectionBindingViewport attribute on elements)
  • Array.prototype.includes

Example

var h = require('mutant/html-element')
var Struct = require('mutant/struct')
var send = require('mutant/send')
var computed = require('mutant/computed')
var when = require('mutant/when')

var state = Struct({
  text: 'Test',
  color: 'red',
  value: 0
})

var isBlue = computed([state.color], color => color === 'blue')

var element = h('div.cool', {
  classList: ['cool', state.text],
  style: {
    'background-color': state.color
  }
}, [
  h('div', [
    state.text, ' ', state.value, ' ', h('strong', 'test')
  ]),
  h('div', [
    when(isBlue,
      h('button', {
        'ev-click': send(state.color.set, 'red')
      }, 'Change color to red'),
      h('button', {
        'ev-click': send(state.color.set, 'blue')
      }, 'Change color to blue')
    )

  ])
])

setTimeout(function () {
  state.text.set('Another value')
}, 5000)

setInterval(function () {
  state.value.set(state.value() + 1)
}, 1000)

setInterval(function () {
  // bulk update state
  state.set({
    text: 'Retrieved from server (not really)',
    color: '#FFEECC',
    value: 1337
  })
}, 10000)

document.body.appendChild(element)

Types

Observables that store data

Value

The classic observable - stores a single value, updates listeners when the values changes.

var Value = require('mutant/value')

var obs = Value()
obs.set(true)
//set listener
obs(value => { 
  // called with resolved value whenever the observable changes
})

This is almost the same as observable and observ. There's only a couple of small differences: you can specify a default value (fallback when null) and it will throw if you try and add a non-function as a listener (this one always got me)

Array

An observable with additional array like methods, which update the observable. The array items can be ordinary values or observables.

Like observ-array but as with struct, emits the same object. No constant shallow cloning on every change. You can push observables (or ordinary values) and it will emit whenever any of them change. Works well with mutant/map.

There's also mutant/set which is similar but only allows values to exist once.

additional methods:

  • array.get(index) get the value at index
  • array.getLength() get the length of the array
  • array.put(index, value) set item at index to value
  • array.push(value) append value to end of array.
  • array.pop() remove item from end.
  • array.shift() remove item from start.
  • array.insert(value, index) equivalent to [].splice(index, 0, value) on a standard js array.
  • array.delete(value) remove the first occurance of value from the array.
  • array.deleteAt(index) remove item at index.
  • array.transaction(fn) apply a series of changes to the array and then update listeners in one go.
  • array.includes(item) check if the array includes item
  • array.indexOf(item) find the index of item in the array
  • array.find(fn) return the first item array for which fn(item) == true
  • array.forEach(fn) iterate over all raw items in the array
  • array.set(array) overwrite the contents of the mutant array with array
  • array.clear() remove all items.

Dict

The complement to Struct - but instead of representing a fixed set of sub-observables, it's a single observable which you can add sub-keys to.

var Dict = require('mutant/dict')
var d = Dict()
d.put('key', 1)
d(function (v) {
  // => {key: 1}
})

additional methods:

  • dict.put(key, value) set property key to value
  • dict.delete(key) remove property key
  • dict.has(key) returns true if key is present.
  • dict.keys() return array of keys.

Set

Represents a collection like Array except without ordering or duplicate values.

additional methods:

  • set.add(value) add value to the set.
  • set.clear() remove all items.
  • set.has() check if item is in the set.
  • set.get(index) get the item at index in the underlying array
  • set.getLength() get the number of items in the set.

Struct

Take a fixed set of observables (or values) and return a single observable of the observed values, which updates whenever the inner values update. Subobservables can by any observable type.

They also have a set function which can be used to push a json object into the nested observables. Any additional set keys will be preserved if you resolve it.

Mostly the same as observ-struct except that it always emits the same object (with the properties changed). This means it violates immutability, but the trade-off is less garbage collection. The rest of the mutant helpers can handle this case pretty well.

They accept a set list of keys that specify types. For example:

var struct = MutantStruct({
  description: Value(),
  tags: MutantSet(),
  likes: Value(0, {defaultValue: 0}),
  props: MutantArray(),
  attrs: MutantDict()
})

You can use these as your primary state atoms. I often use them like classes, extending them with additional methods to help with a given role.

Another nice side effect is they work great for serializing/deserializing state. You can call them with JSON.stringify(struct()) to get their entire tree state, then call them again later with struct.set(JSON.parse(data)) to put it back. This is how state and file persistence works in Loop Drop.

MappedArray

...

MappedDict

...

TypedCollection

This is similar to MappedArray, except with key checking. You can specify a matcher option to define how to decide that two objects are the same (defaults to (rawValue) => rawValue.id), and now any time set is called, instances with the same matcher result will be updated instead of recreated even if the order has changed. This is really useful when turning a collection into DOM elements, and reordering can happen remotely and you are just syncing the entire state every time.

var state = Struct({
  models: TypedCollection(YourModel, {
    matcher: (value) => value.id
  })
})

function YourModel () {
  return Struct({
    id: Value(),
    tags: MutantSet(),
    options: Dict()
  }) 
}

The constructor is called with the rawValue of the object, however you don't need to use this to populate the object as it will also be called with .set. This is just to allow polymorphic typing checks:

var types = {
  Cat () {
    return Struct({
      id: Value(),
      age: Value(),
      ...props
    }) 
  },
  Dog () {
    return Struct({
      id: Value(),
      age: Value(),
      ...props
    }) 
  }
}

var state = Struct({
  pets: TypedCollection((value) => types[value.type](), {
    matcher: (value) => value.id,
    invalidator: (current, newValue) => current.type != newValue.type,
    onAdd: (obj) => console.log('added', resolve(obj)),
    onRemove: (obj) => console.log('removed', resolve(obj)),
  })
})

state.set({
  pets: [
    {id: 1, age: 2, type: 'Dog'},
    {id: 2, age: 9, type: 'Cat'}
  ]
})
// => added {id: 1, type: 'Dog'}
// => added {id: 2, type: 'Cat'}

state.set({
  pets: [
    {id: 2, age: 9, type: 'Cat'},
    {id: 1, age: 3, type: 'Dog'}
  ]
})
// the inner models are updated and order changed, but no new cats/dogs are created

state.set({
  pets: [
    // somehow our dog has turned into a cat!
    // even though the cat has the same ID as the dog, the original object is discarded, and a new one constructed as invalidator returns true
    {id: 1, age: 3, type: 'Cat'},
    {id: 2, age: 9, type: 'Cat'}
  ]
})
// => removed {id: 1, type: 'Dog'}
// => added {id: 1, type: 'Cat'}

ProxyType

A more advanced feature - allow you to create observable slots which allow you to hot-swap observables in/ out of.

  • ProxyCollection
  • ProxyDictionary
  • Proxy

ProxyCollection

...

ProxyDictionary

...

Proxy

...


Transforms

Take one or more observables and transform them into an observable

computed

Take an array of observables, and map them through a function that to produce a custom observable.

//observable that is true if A or B are true

var computed = require('mutant/computed')

var aOrB = computed([a, b], (a, b) => { 
  return a || b 
})

Once again, similar to the observ and observable implementations. It has a few key differences though.

  • It will try to avoid computing if its inputs have not changed.
  • It also won't emit a change if the new computed value is the same as the old one. This helps to prevent additional work duplication and render noise downstream.
  • There is an optional "nextTick" mode that queues up change events until nextTick before computing. But if you call it (value()) in the current tick, it will compute immediately.
  • It acts like a pull through stream: if it doesn't have a sink, no code is run. It won't bind and resolve until it gets a listener itself.
  • It accepts non-observable values too. This makes it possible to pass all state to a shared computed function (no need to waste more memory on those extra closures)
  • If the value returned by the compute function is an observable, it will bind to this and emit the resolve values. Crazy nested computes FTW!
  • These extra features do take up a bit of extra memory so I use an internal prototype (not visible to api) to reduce the footprint below that of observable and observ/computed

map

Apply a function to the value in another observable and update whenever that observable updates. Like computed, but for only one input.

A through transform. It won't do any work and won't listen to its parents unless it has a listener. Calls your function with the original observable object (not the resolve value). You can then return an additional observable value as its result. It has methods on it that make it behave like an array.

One of the most interesting features is its maxTime option. This is a ms value that specifies the max time to spend in a tight loop before emit the changes so far. This makes rendering large datasets to DOM elements much more responsive - a lot more like how the browser does it when it parses html. Things load in little chunks down the page. This for me has made it much easier to build apps that feel responsive and leave the main thread available for more important things (like playing sound).

concat

...

dictToCollection

...

idleProxy

...

keys

...

lookup

...

merge

Merges

reverse

var reverse = require('mutant/reverse')
var reversed = reverse(collection)

Takes an input collection and reverses it. This preserves the raw observables (which is what makes it better than computed).

throttle

...

when

var when = require('mutant/when')

when(
  obs,
  A,      // if true
  B       // if false (optional)
)
// => observable

Behaves like an observable ternary.

Take an observable obs and return the second argument A if obs is truthy. An optional third argument B can be passed and will return if obs is falsey.


Sinks

Stuff that are exit hatches / sinks / make changes in the real world.

  • HtmlElement
  • SvgElement
  • watchAll
  • watchThrottle
  • watch

HtmlElement / h

var textAlign = Value('center')
var someText = Value('some text')
var element = h('div', {style: {'text-align': textAlign}}, [
  h('p.text', someText),
  h('p.text', [
    'Text with ', h('strong', 'formatting'), ' and a ', h('a', {href: '/url'}, 'hyperlink')
  ]),
])

A fancy wrapper around document.createElement() that allows you to create DOM elements (entire trees if needed) without setting lots of properties or writing html. It just returns plain old DOM elements that can be added directly to the DOM.

This follows hyperscript syntax: h('tagName', {...properties}, [childNodes]). The properties section is optional.

You can add observables as properties and when the observable value changes, the DOM magically updates. You can also return one or more DOM elements. Cleanup is automatic (when removed from DOM using MutationObserver). It's a lot like pull streams: the DOM acts as a sink. If an element created by mutant is not in the DOM, it doesn't listen to its observable properties. It only resolves them once it is added, and if it is removed unlistens again.

Properties

It is important to note that you are specifying properties not attributes. So you use the DOM name instead of the HTML name. For example className instead of class. Or playsInline instead of playsinline. Check out this stack overflow topic for more info: What is the difference between properties and attributes in HTML?.

Almost all of the properties work the same way they do when create DOM elements using document.createElement, but there are a few special differences:

  • classList: You can specify an array of classes when creating the element, and the individual classes can be observables. e.g. h('div', {classList: ['class', when(value, 'a', 'b')]})
  • events: Due to the way observables work in Mutant (they're just functions), unfortunately you can't use the onclick style properties to add event handlers (unless wrapped with an observable). You instead add events using the events property or the ev-eventname shorthand. e.g. h('div', {events: {click: clickHandler}}) or h('div', {'ev-click': clickHandler})
  • styles: This uses the CSS attribute names of styles (e.g. 'text-align' instead of 'textAlign'). Each value can be it's own observable, allowing you to tie specific styles directly to state e.g. h('div', {styles: {'color': 'red', 'margin-top': when(spacedOut, '10px', '0px')}})
  • hooks: Specify functions to be run on this element when added and removed from the DOM. Can be used to add custom behaviors, see section below for more info.
  • attributes: Allows you to specify attributes instead of properties (if you need this for some reason, e.g. ARIA attributes), each attribute can be data bound just like with styles and dataset.
  • dataset: Add data to elements. These will be available on the element as dataset.keyName and as an attribute data-key-name. You can also use the data- shorthand directly as a property. Each data item can be bound to observable just like styles and attributes.

You can also specify an intersectionBindingViewport on scrolling elements if you would like the elements to only be bound (live) when they are in the viewport. You can specify true or {rootMargin: VALUE}. See Intersection Observer API - rootMargin for details.

Events

As mentioned above, you can't use the onclick style events, instead you must add them using events or ev-click style handlers. This is equivalent to element.addEventListener.

var element = h('div', {
  events: {
    click: function (ev) {
      // this works just like the handler on addEventListener
    }
  }
})

Or using shorthand:

var element = h('div', {
  'ev-click': function (ev) {
    // this works just like the handler on addEventListener
  }
)

However this method can use a lot of memory if you are adding events to many different elements. If the event handlers are the same, but specified inline every time, this is a waste. Here's how you can optimise this with send:

var send = require('mutant/send') // or const {h, send} = require('mutant')

var element = h('div', {
  'ev-click': send(sharedHandler, {options})
)

function sharedHandler (options) {
  // handle the event here
  // send already calls `preventDefault`
  // you can access the raw event using this.event
}

Hooks

Hooks allow you to add special behaviors to elements. You can use the for data-binding, or custom components, or even merging in other view/templating libraries.

Please note that hooks are not run until the element is actually in the DOM. If the same element is added and removed, the hooks will be run multiple times.

In this example, we use hooks to bind an input element to state:

var h = require('mutant/h')
var watch = require('mutant/watch')
var Value = require('mutant/value')
var watchEvent = require('mutant/watch-event')

var value = Value('default')
var input = h('input', {type: 'text', hooks: [ValueHook(value)]})

function ValueHook (observable) {
  return function (element) {
    // this function is run when the element is added to the DOM
    var unwatch = watch(observable, function (value) {
      element.value = value
    })

    var unwatchElement = watchEvent(element, 'input', function () {
      observable.set(element.value)
    })

    return function onRemove () {
      // this function is called when the element is removed from the DOM
      // we'll use it to clean up our event handlers
      unwatch()
      unwatchElement()
    }
  }
}

SvgElement / svg

Very similar to h above, except works for svg elements.

const { svg } = require('mutant')
let element = svg('svg', { width: 400, height: 300 }, [
  svg('circle', { fill: 'lime', cx: 100, cy: 250, r: 20 }),
  svg('rect', { fill: 'red', x: 50, y: 50, width: 300, height: 100 })
])
document.body.append(element)

watch

  • This is a generic sink. Almost the same as listening to a value using value(function (v) { }) except that it emits the initial value too.
  • It also accepts non-observable objects and will just emit their value once and then never all again.
const {Value, watch} = require('mutant')

var obs = Value('observable')

// immediately logs out the current value
var unwatch = watch(obs, (value) => {
  console.log(value)
})

// logs out again
obs.set('new value')

// stop watching
unwatch()

// this no longer logs out
obs.set('new value')

// watching a non observable object just runs once
var notObs = 'plain old value'
watch(notObs, (value) => {
  console.log(value)
})

watchAll

Just like watch, except you can provide an array of values to watch and they will all be outputted. Kind of like computed.

watchThrottle

Just like watch except has an additional `throttle' param that allows you to prevent the watcher from being called faster than the specified duration.

var value = Value()

// change the value once every 50ms
setInterval(() => {
  value.set(Date.now())
}, 50)

watchThrottle(value, 200, (v) => {
  // only called a maximum of once every 200 ms
})

Helpers

A grab bag of useful things for dealing with mutant stuff. A lot of these are used internally, but are useful more generally

  • channel
  • forEachPair
  • forEach
  • isObservable
  • onceIdle
  • resolve
  • watchAnimationFrame
  • watchEvent
  • send

channel

Creates an observable like object for broadcasting events with no permanent state.

  var channel = MutantChannel()
  var unwatch = channel.listen((value) => {
    console.log(value) // => value
  })
  channel.broadcast('value')

forEach

You can run this on ordinary or observable objects, and it will loop over every item. Mostly just a convenience function to make it easier to work with different kinds of objects (almost but not quite resolve(obj).forEach).

forEachPair

Like forEach above, except can be used on Dict / lookup objects to loop over every key and value pair.

isObservable

Returns true if the provided object is likely to be an observable. This isn't a perfect check however, as observables in mutant are defined as functions that have exactly one argument.

const {Value, isObservable} = require('mutant')
var obs = Value('observable')
var notObs = 'plain old value'

isObservable(obs) // => true
isObservable(notObs) // => true

// WATCH OUT
isObservable(isObservable) // => true (YES, THAT's RIGHT, WATCH OUT FOR THIS!!! Functions with a single argument are detected as observables -- hopefully addressed with a big mutant rewrite one day)

onceIdle

delay a function until the next idle callback without hammering the requestIdleCallback api

var onceIdle = require('mutant/once-idle')
onceIdle(function () {
  //called once, at some later point (after rendering and such)
})

resolve

A convenience function that gets the value of an observable, or just returns the value if not an observable. Handy when you don't know if the value you are dealing with is an observable or not.

const {Value, resolve} = require('mutant')

function printValue (valueOrObservable) {
  console.log(resolve(valueOrObservable))
}

// both of these print out their values
printValue('Hello')
printValue(Value('world'))

watchAnimationFrame

A convenience wrapper around window.requestAnimationFrame. Quickly set up an animation loop (listener gets called every frame), and returns a function that can be called to stop the loop. Very useful with hooks.

var watchAnimationFrame = require('mutant/watch-animation-frame') // or const {watchAnimationFrame, h} = require('mutant')
var unwatch = watchAnimationFrame(element, 'click', function (ev) {
  // this is called ~60 times a second!
})

// until you call the unwatch function, which stops the loop:
unwatch()

watchEvent

A convenience wrapper around element.addEventListener. Allows you to observe an event changing, but returns a function that can be called to remove the event handler. Very useful with hooks.

var watchEvent = require('mutant/watch-event') // or const {watchEvent, h} = require('mutant')
var element = h('div', 'Hello!')
var unwatch = watchEvent(element, 'click', function (ev) {
  // do stuff
})

// clean up event handler
unwatch()

See the hooks example above under HtmlElement for more a more realistic use case!

send

Used to create memory efficient event handlers. See Events example under HtmlElement.


License

MIT

More Repositories

1

loop-drop-app

[unmaintained] MIDI looper, modular synth and sampler app built using Web Audio and Web MIDI APIs
JavaScript
823
star
2

web-audio-school

An intro to the Web Audio API by a series of self-guided workshops.
JavaScript
402
star
3

notevil

Evalulate javascript like the built-in javascript eval() method but safely.
JavaScript
196
star
4

msi-packager

Build MSI (Windows Installer) packages on Mac and Linux
JavaScript
85
star
5

rust-loop-drop

[WIP] Midi-only version of Loop Drop for running on low power machines like Raspberry Pi and Beaglebone
Rust
53
star
6

soundbank

A collection of triggerable Web Audio API audio slots, supporting audio routing, midi input and value providers.
JavaScript
52
star
7

micro-css

A CSS preprocessor that provides a simplified object orientated approach to css. The syntax is very similar to CSS but encourages better reuse of classes and discourages high specificity.
JavaScript
48
star
8

web-midi

Web MIDI API stream based wrapper
JavaScript
46
star
9

bopper

⏰ Streaming clock source for scheduling Web Audio events rhythmically
JavaScript
43
star
10

patchwork-next

Now located at ssbc/patchwork!
JavaScript
36
star
11

soundbank-pitch-shift

Simple pitch shifter for Web Audio API based on delay nodes. Extends Jungle by Chris Wilso.
JavaScript
34
star
12

audio-slot

Web Audio API FRP wrapper for creating, routing, and triggering AudioNodes.
JavaScript
33
star
13

adsr

UNMAINTAINED: Attack, decay, sustain, release envelope for automating Web Audio API AudioParams.
JavaScript
30
star
14

freeverb

⛪ A Web Audio implementation of freeverb (Schroeder Reverberator)
JavaScript
29
star
15

ditty

🔃 Schedule playback for a loop sequence of Web Audio events (e.g. midi notes) using bopper clock source.
JavaScript
26
star
16

audio-rms

〰️ Connect a Web Audio API AudioNode and stream out the realtime RMS audio level.
JavaScript
26
star
17

wave-recorder

💿 Record WAVE files using Web Audio API and persist with Web FileSystem API.
JavaScript
25
star
18

audio-buffer-stream

Get a PCM stream from input AudioBuffers (Web Audio API). Can be used to implement a streaming audio recorder.
JavaScript
23
star
19

soundbank-reverb

Simple Web Audio API based reverb effect.
JavaScript
22
star
20

jsconfasia-talk-2015

I Play the JavaScript - JavaScript, Midi and Live Computer Music!
HTML
20
star
21

web-fs

UNMAINTAINED: Node's fs module for browsers using Web FileSystem API
JavaScript
20
star
22

patchtron

Yet another SSB client! Probably gonna be Patchwork 4.0, but for now is missing a lot of things and under pretty serious development
JavaScript
17
star
23

custom-audio-node

Create your own AudioNodes with AudioParams for using with the Web Audio API.
JavaScript
14
star
24

dirty-git

List git repos that have dirty working directories (uncommited changes)
JavaScript
13
star
25

lfo

Low frequency oscillator for automating Web Audio API AudioParams.
JavaScript
12
star
26

loop-grid

Make grid based controllers that trigger events and record loops using soundbank and loop-recorder.
JavaScript
12
star
27

soundbank-granular

Sample based granular sythesis and timestretch
JavaScript
11
star
28

observ-midi

Observe and write to midi stream as a single value, struct, array or grid.
JavaScript
10
star
29

array-grid

Two-dimensional implementation of ndarray to avoid dynamic code generation eval.
JavaScript
10
star
30

knob

Canvas knob widget for the browser (touch compatible). Based on jQuery Knob by Anthony Terrien.
JavaScript
9
star
31

midi-looper

Stream based midi loop maker. Buffers all input then creates loops on demand.
JavaScript
9
star
32

audio-buffer-range-decoder

🕞 Decode specified ranges of wave files on disk to AudioBuffers.
JavaScript
9
star
33

midi-controller

Create buttons and note matrices from duplex midi streams for midi controllers such as Launchpad.
JavaScript
8
star
34

audio-param-transform

Apply multiple transforms with custom functions to Web Audio API AudioParams.
JavaScript
7
star
35

nodepdx-talk-2016

Portland flavoured version of "I Play The JavaScript" or "I still play the JavaScript" given on the 21st of June 2016
HTML
6
star
36

observ-fs

Create observable file system scopes using observ pattern.
JavaScript
6
star
37

soundbank-sample

DEPRECATED: Sample player AudioNode source extended with automatable transpose, tuning and amp.
JavaScript
6
star
38

observ-grid

An observable array-grid.
JavaScript
6
star
39

pull-hyperscript

hyperscript as a pull-stream source. Allows streaming the view to the browser as it continues to render.
JavaScript
6
star
40

remote-camera

Example electron app that creates a web server and then streams the remote web-cam of connected user to the local machine.
JavaScript
6
star
41

mutant-pull-reduce

Reduce the output of a pull-stream into a mutant observable.
JavaScript
6
star
42

soundbank-oscillator

Oscillator AudioNode source extended with automatable amplitude and midi note params.
JavaScript
5
star
43

audio-timeline

DEPRECATED: merged into loop-drop-app
JavaScript
5
star
44

midi-grid

Map a duplex midi stream to observable input and output value grids.
JavaScript
5
star
45

soundbank-slice

Use with soundbank-inherit to slice an audio sample across the desired amount of audio-slots.
JavaScript
5
star
46

wave-file-stream

PCM Wave File stream for Node and browsers using Web FileSystem API (via web-fs).
JavaScript
5
star
47

nodejs-wellington-talk-september-2015

Loop Drop and Electron - Node.js Wellington, 2 September 2015
JavaScript
5
star
48

soundbank-overdrive

A simple audio distortion effect based on wave shaping with automatable filter and gain controls.
JavaScript
5
star
49

audio-slot-param

Link and transform schedule-based observables and connect to Web Audio AudioParams.
JavaScript
4
star
50

midi-grabber

Stream midi data in and create temporarily route ranges to specific callbacks.
JavaScript
4
star
51

loop-recorder

Buffers all streamed in trigger events and creates range loops on demand.
JavaScript
4
star
52

tone-modular

Special build of Tone.js that allows requiring of individual components and avoids the global AudioContext. This make it much more browserify friendly and easier to use with existing code or other libraries.
JavaScript
4
star
53

soundbank-dipper

A global side-chain compressor for the Web Audio API. Modulate the amplitude of AudioNodes based on the amplitude of other AudioNodes.
JavaScript
4
star
54

soundbank-delay

Basic delay processor AudioNode with feedback, filter and wet/dry AudioParams.
JavaScript
3
star
55

campjs-v-loop-drop-talk

JavaScript
3
star
56

callify

Create browserify transforms that change or inline external module function calls.
JavaScript
3
star
57

lookup-grid

Position two-dimensional ndarrays on an x/y grid for lookup of individual coords and values.
JavaScript
3
star
58

midi-repeater

Continuously trigger held midi notes using clock input
JavaScript
3
star
59

midi-looper-launchpad

Launchpad control for midi-looper
JavaScript
3
star
60

loop-drop-engine

JavaScript
3
star
61

wave-view

SVG based PCM waveform renderer for the browser
JavaScript
3
star
62

campjs-v-hack

JavaScript
3
star
63

observ-node-array

Populate an observable array from node descriptors.
JavaScript
3
star
64

observ-fs-audio-buffer

Observable AudioBuffer for use with fs.
JavaScript
3
star
65

audio-meddle

Route Web Audio API audio nodes through schedulable chains of processor nodes.
JavaScript
3
star
66

ableton-hack

hack hack
JavaScript
3
star
67

observ-default

Observ with default value on null.
JavaScript
3
star
68

audio-splatter

JavaScript
3
star
69

realtime-templates

DEPRECATED: Render views on the server (using standard HTML markup) that the browser can update in realtime when the original data changes.
JavaScript
3
star
70

json-signer

Signs JSON objects using a private key allowing a server to ensure an object has not been tampered with.
JavaScript
3
star
71

observer-stack

Wrap an observable so that only the top most observer receives notifications.
JavaScript
2
star
72

throttle-observ

Throttles observ object broadcast to specified rate.
JavaScript
2
star
73

loop-mpkmini

loop-grid bindings for Akai MPK Mini controller
JavaScript
2
star
74

disco-textures

JavaScript
2
star
75

soundbank-scale

Use with soundbank-inherit to distribute a series of audio-slots across a musical scale.
JavaScript
2
star
76

pull-cat-map

Map pull-streams to other pull-streams then concat together
JavaScript
2
star
77

soundbank-inherit

Inherit descriptor from target audio slot and override specified attributes.
JavaScript
2
star
78

midi-port-holder

Bind to midi port by name and expose switchable duplex stream.
JavaScript
2
star
79

loopjs-packager

JavaScript
2
star
80

observ-transform

Observable transform (with args) based on observ-* pattern.
JavaScript
2
star
81

soundbank-multi

Repeat template descriptor for every item in input array, replacing placeholder with current item.
JavaScript
2
star
82

contextdb

Use json-context with leveldb. Contexts are automatically generated from matchers, and provides ability to watch matchers for realtime notifications.
JavaScript
2
star
83

jsconfasia-talk-2016-livejs

HTML
2
star
84

loop-drop-hack

JavaScript
2
star
85

window-stream

Stream data between browser windows using postMessage
JavaScript
2
star
86

loopjs-www

Loop Drop marketing/purchase/download/help website
HTML
2
star
87

soundbank-slide

Modulator to implement time sliding between grouped values.
JavaScript
1
star
88

loop-drop-sample-project

Sample Project for Loop Drop
1
star
89

loop-drop-server

JavaScript
1
star
90

forest-songs

JavaScript
1
star
91

soundbank-slot-editor

Visual node editor for soundbank slots.
JavaScript
1
star
92

loop-grid-repeater

A note repeater transform for loop-grid.
JavaScript
1
star
93

loop-drop-setup

DEPRECATED: merged into loop-drop-app
JavaScript
1
star
94

moontune

JavaScript
1
star
95

loop-stream

Stream Loop Drop playback data out on a websocket
JavaScript
1
star
96

elementize

Convert HTML into an array of DOM Elements
JavaScript
1
star
97

loop-drop-project

Provides scoped object access and persistence layer for Loop Drop objects.
JavaScript
1
star
98

observ-graph

Observable typed collections.
JavaScript
1
star
99

loop-drop-audio-context

AudioContext prepopluted with all the soundbank modules used in Loop Drop
JavaScript
1
star
100

loop-grid-holder

Beat stutter/looper transform for loop-grid.
JavaScript
1
star