demo 1
demo 2
demo 1
demo 2
Before reading Rosa Menkman’s Glitch Studies Manifesto, I mostly saw glitches as problems that good programming should prevent. In coding, we are usually trained to build systems that handle failures so smoothly that users never notice them. Because of that, I had always thought of noise as something unwanted. Menkman’s discussion changed that perspective by showing that noise and glitches can do more than interrupt a system — they can expose the hidden structures behind technology and question the idea that digital media must always be clean and flawless.
Even though I still understand why people prefer smooth and reliable devices, the reading made me value noise in a different way. I can see this reflected in today’s renewed interest in vintage cameras and older technologies, where imperfections are often appreciated rather than avoided. Glitch art does something similar: it turns error into expression and gives artists a way to challenge both technological standards and larger social or political systems. What stands out to me most is that meaning depends on perspective. The artist may see intention and structure in the glitch, while the viewer may still experience it as disruption. That made me realize that our idea of a “perfect” program or technology is not fixed, but shaped by how we choose to interpret it.
I originally had a more culturally oriented idea in mind for this composition, which I hope to return to later, but I found myself lacking inspiration and direction at this time. To reset, I went back to the class materials, the dirt samples, and revisited the class basics by running patterns again. From there, the piece began to grow more naturally and shifted into an exploration of buildup. I initially wanted to construct everything from my own sampled slices, but ran into challenges shaping them into clean drops and transitions, so the work became a blend of templates and personal material. This led me to a more open and exploratory process building intensity, compressing into darker moments, and then opening back up again.
Tidal
setcps (135/60/4)
visSec = \n -> ccv (pure $ fromIntegral n) # ccn "0" # s "midi"
visSpd = \p -> ccv p # ccn "1" # s "midi"
visHit = \p -> ccv p # ccn "2" # s "midi"
visDark = \p -> ccv p # ccn "3" # s "midi"
visGeom = \p -> ccv p # ccn "4" # s "midi"
visBus = \sec spd hit dark geom ->
stack
[ visSec sec
, visSpd spd
, visHit hit
, visDark dark
, visGeom geom
]
introDrone =
slow 8 $
slice 40 "3" $ s "sudan"
# speed 0.45
# room 0.8
# legato 2
# gain 0.9
airPad =
n (slow 4 "")
# sound "supersaw"
# legato 1.6
# lpf (range 500 1800 $ slow 6 sine)
# resonance 0.22
# room 0.7
# gain 0.45
# shape 0.18
voiceLine = stack
[ fast 2 $
s "simplesine"
>| note (arp "updown" (scale "minor" ("[0,2,4,6]" + "") + "c4"))
# gain 0.62
# lpf 2600
# room 0.55
, s "simplesine"
>| note (scale "minor" ("[,0,2](3,8)") + "c4")
# gain 0.58
# room 0.6
]
versePerc =
stack
[ s "~ cp" # room 0.45 # gain 0.95
, fast 2 $
s "hh*2 hh*2 hh*2 "
# room 0.65
# gain (range 0.9 1.15 rand)
]
habeshaTop =
slice 40 "18" $ s "habesha:1"
# legato 1
# room 0.55
# gain 0.95
kickMain =
s "[, ~ 808:3]"
# room 0.35
# gain 1.0
leadDrop =
n (fast 2 "")
# sound "supersaw"
# legato 0.2
# lpf (range 160 4200 $ slow 3 sine)
# room 0.28
# gain 0.72
# krush 5
# shape 0.3
# pan (slow 2 sine)
buildHat =
stack
[ s "~ cp" # room 0.45 # gain 1.0
, fast 2 $
s "hh*2 hh*2 hh*2 "
# room 0.65
# gain (range 0.95 1.2 rand)
]
# speed (slow 4 $ range 1 2 saw)
buildSnare =
qtrigger $ filterWhen (>=0) $ seqP
[ (0,1, s "feel:2*4")
, (1,2, s "feel:2*8")
, (2,3, s "feel:2*16")
, (3,4, s "feel:2*32")
]
# room 0.25
# hpf (slow 4 $ (1000 * saw + 200))
# speed (slow 4 $ range 1 3 saw)
# gain 0.95
buildPulse =
s ""
# gain 0.8
# lpf (slow 4 $ range 300 2200 saw)
# room 0.2
buildSynth =
n (slow 2 "")
# sound "supersaw"
# legato 0.8
# gain 0.5
# hpf (slow 4 $ range 200 1600 saw)
# lpf (slow 4 $ range 1200 5000 saw)
# room 0.45
# shape 0.25
kickFill =
s "[808bd:1 [~ 808bd:1*3]] [808bd:1 ~ 808bd:1*2]"
# room 0.45
# speed (range 7.6 2.1 saw)
# krush 10
# gain 1.0
dropKick =
s "[bd*2 ] [~ bd*2]"
# gain 1.15
# room 0.25
# shape 0.32
dropBass =
n ""
# sound "supersaw"
# octave 3
# legato 1
# gain 0.95
# lpf (range 120 700 $ slow 2 sine)
# room 0.2
# krush 6
dropPerc =
s ""
# room 0.85
# speed "2 1"
# gain 1.2
# squiz 1.05
# up "-2"
dropMetal =
s "[~ [hc*4 hc*8] ~ hc*16]"
# gain 0.7
# hpf 3500
# room 0.15
dropStab =
n ""
# sound "supersaw"
# legato 0.15
# gain 0.7
# room 0.25
# lpf 1800
# krush 8
silenceAll = do
d1 silence
d2 silence
d3 silence
d4 silence
d5 silence
d6 silence
d7 silence
d8 silence
section_intro = do
d1 $ visBus
0
(slow 8 $ range 8 20 sine)
(struct "t(3,8)" $ range 10 25 saw)
(slow 8 $ range 95 70 sine)
(slow 8 $ range 10 25 sine)
d2 introDrone
d3 airPad
d4 silence
d5 silence
d6 silence
d7 silence
d8 silence
section_verse = do
d1 $ visBus
1
(slow 6 $ range 18 35 sine)
(struct "t(3,8)" $ range 20 45 saw)
(slow 6 $ range 80 60 sine)
(slow 4 $ range 18 40 saw)
d2 voiceLine
d3 versePerc
d4 airPad
d5 habeshaTop
d6 silence
d7 silence
d8 silence
section_build1 = do
d1 $ visBus
2
(slow 4 $ range 30 75 saw)
(struct "t(3,8)" $ range 35 80 saw)
(slow 4 $ range 65 40 saw)
(slow 4 $ range 35 75 saw)
d2 $ qtrigger $ filterWhen (>=0) $ seqP
[ (0,3, voiceLine)
, (3,4, kickFill)
]
d3 buildHat
d4 buildSnare
d5 buildPulse
d6 buildSynth
d7 silence
d8 silence
section_build2 = do
d1 $ visBus
3
(segment 128 $ range 65 120 $ saw)
(segment 64 $ struct "" $ range 60 127 saw)
(segment 64 $ range 45 20 saw)
(segment 64 $ range 60 120 saw)
d2 buildHat
d3 buildSnare
d4 buildPulse
d5 buildSynth
d6 $ qtrigger $ filterWhen (>=0) $ seqP
[ (0,1, s "feel:2*4")
, (1,2, s "feel:2*8")
, (2,3, s "feel:2*16")
, (3,4, s "feel:2*32")
]
# room 0.2
# speed (slow 4 $ range 1 4 saw)
# hpf (slow 4 $ range 1200 8000 saw)
d7 kickFill
d8 silence
section_drop = do
d1 $ visBus
4
(slow 2 $ range 110 70 sine)
(struct "" $ range 90 127 square)
(slow 2 $ range 18 35 sine)
(slow 2 $ range 85 45 saw)
d2 dropKick
d3 dropBass
d4 dropPerc
d5 dropStab
d6 dropMetal
d7 silence
d8 silence
section_after = do
d1 $ visBus
5
(slow 6 $ range 25 45 tri)
(struct "t(3,8)" $ range 30 55 saw)
(slow 6 $ range 70 55 sine)
(slow 8 $ range 25 40 tri)
d2 kickMain
d3 voiceLine
d4 airPad
d5 habeshaTop
d6 silence
d7 silence
d8 silence
section_outro = do
d1 $ visBus
6
(segment 128 $ slow 8 $ range 40 8 sine)
(segment 128 $ slow 8 $ range 35 5 sine)
(segment 128 $ slow 8 $ range 80 100 sine)
(segment 128 $ slow 8 $ range 35 8 sine)
d2 introDrone
d3 silence
d4 silence
d5 silence
d6 silence
d7 silence
d8 silence
goI = section_intro
goV = section_verse
goB1 = section_build1
goB2 = section_build2
goD = section_drop
goA = section_after
goO = section_outro
goI
goB1
goB2
goD
goB1
goD
goA
goO
silenceAll
hush
Hydra
hush()
const ccv = (n, fallback = 0) => () => {
try {
return (cc[n] !== undefined ? cc[n] : fallback) / 127
} catch (e) {
return fallback / 127
}
}
const SECTION = ccv(0, 0)
const SPEED = ccv(1, 20)
const HIT = ccv(2, 0)
const DARK = ccv(3, 80)
const GEOM = ccv(4, 20)
const W = () => window.innerWidth
const H = () => window.innerHeight
const aspect = () => H() / W()
const colorFold = (src, n = 6) =>
new Array(n).fill().reduce(
(a) => a.colorama(() => 0.002 + GEOM() * 0.02),
src
)
const triGrid = () =>
shape(3, 0.32, 0.001)
.rotate(() => time * 0.04 + SPEED() * 0.4, () => 0.02 + HIT() * 0.08)
.repeat(
() => 2 + Math.floor(GEOM() * 6),
() => 2 + Math.floor(GEOM() * 4)
)
.scrollX(() => 0.02 * Math.sin(time * 0.3))
.scrollY(() => 0.02 * Math.cos(time * 0.2))
.luma(0.15, 0.2)
const quadGrid = () =>
shape(4, 0.45, 0.0001)
.repeat(
() => 2 + Math.floor(GEOM() * 5),
() => 2 + Math.floor(GEOM() * 5)
)
.rotate(() => time * 0.02 + SPEED() * 0.2)
.scale(1, aspect(), 1)
.luma(0.2, 0.15)
const movingOsc = () =>
osc(
() => 8 + SPEED() * 65,
() => 0.015 + SPEED() * 0.08,
() => 0.4 + HIT() * 3.2
)
.posterize(() => 3 + Math.floor(GEOM() * 4))
.kaleid(() => 3 + Math.floor(SECTION() * 8))
.scale(1, aspect(), 1)
.color(
() => 0.5 + DARK() * 0.4,
() => 0.15 + SECTION() * 0.35,
() => 0.35 + GEOM() * 0.4
)
const texture = () =>
noise(
() => 1.5 + GEOM() * 8,
() => 0.02 + SPEED() * 0.03
)
.pixelate(
() => 8 + GEOM() * 50,
() => 8 + GEOM() * 40
)
.luma(0.35, 0.25)
const darkWash = () =>
solid(0, 0, 0)
.add(
osc(
() => 6 + SPEED() * 18,
0.01,
0
)
.rotate(() => time * 0.01)
.luma(0.25, 0.25)
.color(0,0,0),
() => 0.15 + (1 - DARK()) * 0.55
)
const accentLines = () =>
osc(
() => 12 + HIT() * 35,
0.01,
1
)
.rotate(() => Math.PI/4 + time * 0.01)
.luma(0.78, 0.18)
.color(
() => 0.15 + SECTION() * 0.18,
() => 0.25 + DARK() * 0.2,
() => 0.35 + DARK() * 0.25
)
.mult(quadGrid())
.mult(
osc(3,0.02,0)
.rotate(Math.PI/2)
.luma(0.6,0.2)
)
const scene = () =>
colorFold(
movingOsc()
.modulate(
texture(),
() => 0.03 + GEOM() * 0.16
)
.mult(triGrid().add(quadGrid(), 0.5)),
8
)
.add(texture(), () => 0.05 + GEOM() * 0.08)
src(o1)
.modulateRotate(
noise(
() => 1 + GEOM() * 5,
() => 0.01 + SPEED() * 0.02
),
() => 0.003 + HIT() * 0.05
)
.scale(() => 1.0005 + HIT() * 0.01)
.rotate(() => 0.0008 + SPEED() * 0.01)
.blend(scene(), 0.82)
.add(accentLines(), () => 0.04 + DARK() * 0.06)
.add(darkWash(), () => 0.2 + (1 - DARK()) * 0.45)
.saturate(() => 1 + DARK() * 1.2)
.contrast(() => 1.0 + HIT() * 0.3)
.brightness(() => -0.18 + DARK() * 0.18)
.out(o1)
render(o1)
Rhythmic traditions of Ethiopia and Sudan beats with the pulse of contemporary electronic music. The piece weaves sample Eskista rhythms, Nubian percussion, and krar(traditional music instrument) melodies.
Kurokawa’s perspective on nature is grounded in a deep patience that I find interesting. He mentioned that nature doesn’t change overnight but evolves gradually, and he applies that same logic to his own work. He isn’t interested in the frantic race to keep up with every new tech development. Instead, he focuses on what he calls his “incremental evolution.” It makes his process feel much more intentional, like he is growing his art the same way a forest grows, rather than just chasing the next big update.
The author also mentioned Kurokawa’s two conceptual hangers, which are synaesthesia and the deconstruction of nature. Seeing his ATOM performance on YouTube really made those ideas click for me. It was not just a show. It felt like watching nature get dismantled and put back together in real time. The way the visuals fractured and then snapped back together in milliseconds felt exactly like the time design the writer described. It reinforced that idea of absolute instability, showing that nothing is actually solid and everything we see is just fragments in flux.
What I took away most was his wabi-sabi vibe. In a world where everyone is obsessed with the latest AI or new gadgets, he is just chilling and totally indifferent to the tools. He cares about the evolution of the work rather than the specs of the computer. It makes his cataclysmic walls of noise feel a lot more human. He is just a guy trying to find a bit of order in the chaos of the universe. He moves between the microscopic and the cosmic without ever losing his footing.
Strudel represents a significant evolution in accessible music live coding, porting the sophisticated pattern language of TidalCycles from Haskell to JavaScript for entirely browser-based performance.
The project emerged in early 2022 when Alex McLean (creator of TidalCycles) began porting Tidal’s pattern representation to JavaScript. Developer Felix Roos discovered this early work and built a complete browser system around it. After intensive collaborative development, Strudel was formally presented at the 2023 International Conference on Live Coding in Utrecht, establishing it within the “Uzulangs” family of Tidal-inspired environments.
While Strudel faithfully preserves Tidal’s cyclic time model and pattern operations, several distinctions matter:
No installation required. Unlike TidalCycles, which demands Haskell, SuperCollider, and SuperDirt setup, Strudel runs immediately in any modern browser. This dramatically lowers the entry barrier for newcomers and educational contexts.
JavaScript, not Haskell. The syntax feels familiar to web developers, though the underlying pattern concepts remain consistent with Tidal’s approach.
Flexible output routing. Strudel includes WebAudio synthesis directly, but can also drive MIDI hardware, send OSC to SuperCollider/SuperDirt, connect via WebSerial, or route to CSound, making it adaptable to various workflows.
Strudel’s REPL transpiles code into Pattern objects using Acorn and Escodegen parsers. A scheduler queries these patterns at regular intervals, generating musical events (called “Haps”) while maintaining Tidal’s characteristic approach: events compress into fixed cycle lengths, enabling dense polymetric structures without tempo changes.
The result is a practical tool for algorave performance, classroom teaching, and studio sequencing that preserves TidalCycles’ creative philosophy while embracing web accessibility.
Explore at strudel.cc.
After reading this, the concept that stuck with me most is “thinking in public.” In my experience as a student and a developer, coding is usually taught as a semi-private, stressful process where you hide your messy pseudo code and only show the final, polished result. The idea of projecting your raw thoughts and errors onto a wall for an audience to see feels like a massive shift. It turns programming from a rigid engineering task into something more like a conversation. I like the way the text describes it as “unthinking” the way we usually work. It makes the computer feel less like a cold tool and more like a creative partner you’re collaborating with in real time.
The most interesting takeaway for me was the critique of “seamless” technology. We’re so used to interfaces being invisible and easy that we forget there is a programmed system actually directing our behavior. By showing the code, live coders are essentially stripping away that illusion. It’s a bit of a reality check. It makes me realize that when we don’t understand the software we use, we’re just passive consumers. This perspective reclaims the idea of being a “user” as someone who actually has autonomy. It’s definitely made me rethink the relationship I have with my own laptop and the software I run on it every day.