Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Listen to your web pages
@R4meau

This comment has been minimized.

Copy link

@R4meau R4meau commented Feb 14, 2020

Haha, I wonder what kind of debugging you're into. XD

@dawidjaniga

This comment has been minimized.

Copy link

@dawidjaniga dawidjaniga commented Feb 14, 2020

Great idea πŸ‘ πŸ₯‡

@vprasanth

This comment has been minimized.

Copy link

@vprasanth vprasanth commented Feb 14, 2020

This hilarious! thanks!

@tkesgar

This comment has been minimized.

Copy link

@tkesgar tkesgar commented Feb 14, 2020

This is cool stuff, thank you for sharing! πŸ‘ πŸ‘ πŸ‘

@LXSMNSYC

This comment has been minimized.

Copy link

@LXSMNSYC LXSMNSYC commented Feb 15, 2020

I can never hear my websites the same way again. I need to release these souls from their agony.

@asdfx86

This comment has been minimized.

Copy link

@asdfx86 asdfx86 commented Feb 15, 2020

Sounds beautiful, love it β™₯πŸ’—

@lenaggar

This comment has been minimized.

Copy link

@lenaggar lenaggar commented Feb 15, 2020

wow! I like it 😁

@mariocesar

This comment has been minimized.

Copy link

@mariocesar mariocesar commented Feb 15, 2020

Make a browser extensions before somebody else does. Take the credit! cool stuff!

@rippling-frontend

This comment has been minimized.

Copy link

@rippling-frontend rippling-frontend commented Feb 15, 2020

I can never hear my websites the same way again. I need to release these souls from their agony.

True that!

@antonkomarev

This comment has been minimized.

Copy link

@antonkomarev antonkomarev commented Feb 15, 2020

Brilliant!

@m00dy

This comment has been minimized.

Copy link

@m00dy m00dy commented Feb 15, 2020

very smart !!!

@SeriousM

This comment has been minimized.

Copy link

@SeriousM SeriousM commented Feb 15, 2020

I can never hear my websites the same way again. I need to release these souls from their agony.

True that!

And add a sound output for network activity!

@R4meau

This comment has been minimized.

Copy link

@R4meau R4meau commented Feb 15, 2020

And add a sound output for network activity!

Now this!

@nessup

This comment has been minimized.

Copy link

@nessup nessup commented Feb 15, 2020

Awesome!

@dsharhon

This comment has been minimized.

Copy link

@dsharhon dsharhon commented Feb 15, 2020

javascript:(function plink_plonk_bookmarklet () {
  /*
  Author: Tom Hicks
  Copy this into a bookmark URL and click on it from any web page that is 
  interactive and doesn't do hard reloads. You will hear your DOM changes as
  different pitches of audio.
  
  I have found this interesting for debugging, but also fun to hear web pages
  render like UIs do in movies.
  */
  const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
  const observer = new MutationObserver(function(mutationsList) {
    const oscillator = audioCtx.createOscillator();

    oscillator.connect(audioCtx.destination);
    oscillator.type = "sine";
    oscillator.frequency.setValueAtTime(
      Math.log(mutationsList.length + 5) * 880,
      audioCtx.currentTime
    );

    oscillator.start();
    oscillator.stop(audioCtx.currentTime + 0.01);
  });

  observer.observe(document, {
    attributes: true,
    childList: true,
    subtree: true,
    characterData: true
  });
})();
@Fortyseven

This comment has been minimized.

Copy link

@Fortyseven Fortyseven commented Feb 15, 2020

Change that stop delay on line 22 to 0.03 on Facebook and SUDDENLY I'M IN THE FUTURE.

@jcraigk

This comment has been minimized.

Copy link

@jcraigk jcraigk commented Feb 15, 2020

This is absolutely brilliant. And useful.

@sbrichardson

This comment has been minimized.

Copy link

@sbrichardson sbrichardson commented Feb 15, 2020

Here's a funny variation that speaks out the counts in different pitches/rates

const speechSynthesis = window.speechSynthesis
const min = 0
const max = 100
const bad = 15 // just a random max to enable 'bad developer' mode

const observer = new MutationObserver(function(mutationsList) {
  const msg = new SpeechSynthesisUtterance()
  const len = mutationsList.length
  
  if (len > bad) {
    msg.text = 'Bad Developer'
  } else {
    const n = len > max ? max : len
    const pitch = ((n - min) / (100 - min)) * 2
    msg.text = len
    msg.rate = 4 - pitch * 4
    msg.pitch = 2 - (pitch * 1.6 * 1.2)
  }

  speechSynthesis.speak(msg)
})

observer.observe(document, {
  attributes: true,
  childList: true,
  subtree: true,
  characterData: true,
})  
@makeworld-the-better-one

This comment has been minimized.

Copy link

@makeworld-the-better-one makeworld-the-better-one commented Feb 16, 2020

Can anyone upload what they hear on some sites?

@larscmagnusson

This comment has been minimized.

Copy link

@larscmagnusson larscmagnusson commented Feb 16, 2020

Hahaha, great work!

@LXSMNSYC

This comment has been minimized.

Copy link

@LXSMNSYC LXSMNSYC commented Feb 16, 2020

Can anyone upload what they hear on some sites?

You'll just hear a Chewbacca Jr. talking

@nathanvogel

This comment has been minimized.

Copy link

@nathanvogel nathanvogel commented Feb 16, 2020

Hahaha great idea! πŸ‘ (could be a nice prank too)
Didn't work on Firefox, but Chrome is βœ”οΈ

@R4meau

This comment has been minimized.

Copy link

@R4meau R4meau commented Feb 16, 2020

I honestly didn't like it at first, then I realized how useful it can actually be :) . So I turned it into a basic Chrome extension: https://github.com/R4meau/plink-plonk

I'll be working on it every Sunday (very slow for now) and I'm open for any contributions at any time. Thanks for the head start @tomhicks.

@iAnatoly

This comment has been minimized.

Copy link

@iAnatoly iAnatoly commented Feb 16, 2020

I have moved out the constants into variables, to be able to play with the settings more easily.
I also added a random component. to make it sound less monotonous:

// origin: https://gist.github.com/tomhicks/6cb5e827723c4eaef638bf9f7686d2d8 ,  tomhicks/plink-plonk.js

const audioCtx = new (window.AudioContext || window.webkitAudioContext)()
var delay = 0.03
var freqbase = 600
var freqrnd = 400
const observer = new MutationObserver(function(mutationsList) {
  const oscillator = audioCtx.createOscillator()

  oscillator.connect(audioCtx.destination)
  oscillator.type = "sine"
  oscillator.frequency.setValueAtTime(
    Math.log(mutationsList.length + 5) * (Math.random()*freqrnd + freqbase),
    audioCtx.currentTime,
  )

  oscillator.start()
  oscillator.stop(audioCtx.currentTime + delay)
})

observer.observe(document, {
  attributes: true,
  childList: true,
  subtree: true,
  characterData: true,
})  

Then you can play with delay and freq on the fly.

@aflemi2

This comment has been minimized.

Copy link

@aflemi2 aflemi2 commented Feb 16, 2020

Love this!

@iAnatoly

This comment has been minimized.

Copy link

@iAnatoly iAnatoly commented Feb 16, 2020

This one randomly decreases/increases tone until it reaches a threshold. Makes it a bit more harmonious:

// origin: https://gist.github.com/tomhicks/6cb5e827723c4eaef638bf9f7686d2d8 ,  tomhicks/plink-plonk.js

const audioCtx = new (window.AudioContext || window.webkitAudioContext)()
var delay = 0.03
// parameters of the random increment/decrement
var freqstart = 600
var freqlow = 400
var freqhigh = 900
var freqspeed = 50
// initial values
var freqinc = 25
var freq = 600

const observer = new MutationObserver(function(mutationsList) {
  const oscillator = audioCtx.createOscillator()

  oscillator.connect(audioCtx.destination)
  oscillator.type = "sine"
  oscillator.frequency.setValueAtTime(
    Math.log(mutationsList.length + 5) * freq,
    audioCtx.currentTime,
  )
  freq += freqinc
  if (freq > freqhigh || freq<freqlow) {
    // reset if we have reached the high or low bound
    freq = freqstart
    freqinc = (Math.random()-0.5)*freqspeed
  }

  oscillator.start()
  oscillator.stop(audioCtx.currentTime + delay)
})

observer.observe(document, {
  attributes: true,
  childList: true,
  subtree: true,
  characterData: true,
})  
@tatthien

This comment has been minimized.

Copy link

@tatthien tatthien commented Feb 17, 2020

Genius!

@epranka

This comment has been minimized.

Copy link

@epranka epranka commented Feb 17, 2020

Nice work! Check this out https://soundcode.now.sh too πŸ™‚

@ttcremers

This comment has been minimized.

Copy link

@ttcremers ttcremers commented Feb 17, 2020

Absolutely wonderful! πŸ˜„

@fbedussi

This comment has been minimized.

Copy link

@fbedussi fbedussi commented Feb 17, 2020

awesome! My computer now sounds like one from a '70s TV serial

@soundmasteraj

This comment has been minimized.

Copy link

@soundmasteraj soundmasteraj commented Feb 17, 2020

Could replace the pulses with Rice Krispies sounds. Now, web == tasty breakfast!

@ricokahler

This comment has been minimized.

Copy link

@ricokahler ricokahler commented Feb 18, 2020

try this on a typing test website. very enjoyable lol

@MarkArts

This comment has been minimized.

Copy link

@MarkArts MarkArts commented Feb 18, 2020

Added quantization and randomness + delay for a cuter effect πŸ˜‡

https://gist.github.com/MarkArts/3d4217f957df8a30802a8cbf962fa204

// origin: https://gist.github.com/tomhicks/6cb5e827723c4eaef638bf9f7686d2d8 ,  tomhicks/plink-plonk.js

/*
Copy this into the console of any web page that is interactive and doesn't
do hard reloads. You will hear your DOM changes as different pitches of
audio.
I have found this interesting for debugging, but also fun to hear web pages
render like UIs do in movies.
*/

// dorian (-)   C     E      F     G-     A     B-   
let scale = [
  264, 330, 352, 391.1, 440, 488.9 
]
scale = scale.concat(scale.map(x=>x*2))

console.log(scale)

function quantize(scale, freq) {
  return scale.reduce(function(prev, curr){
    return (Math.abs(curr - freq) < Math.abs(prev - freq) ? curr : prev);
  });
}

const audioCtx = new (window.AudioContext || window.webkitAudioContext)()
const observer = new MutationObserver(observe)

function observe(mutationsList) {
  // with delay
  delayNote(gain => playNote(mutationsList, gain), 300, 0.2)  
  // without
  // playNote(mutationsList)
}


// Compressor as final stage to prevent clipping
const compressor = audioCtx.createDynamicsCompressor()
compressor.threshold.setValueAtTime(-40, audioCtx.currentTime);
compressor.knee.setValueAtTime(40, audioCtx.currentTime);
compressor.ratio.setValueAtTime(12, audioCtx.currentTime);
compressor.attack.setValueAtTime(0, audioCtx.currentTime);
compressor.release.setValueAtTime(0.25, audioCtx.currentTime);
compressor.connect(audioCtx.destination)

async function playNote(mutationsList, gain = 1) {  
  audioCtx.resume()
  
  const oscillator = audioCtx.createOscillator()
  oscillator.type = "triangle"
  const biquadFilter = audioCtx.createBiquadFilter();
  biquadFilter.type = "lowpass";
  const gainNode = audioCtx.createGain();
  const panNode = audioCtx.createStereoPanner();  
  
  // Setup audio chain 
  oscillator.connect(biquadFilter);
  biquadFilter.connect(gainNode);
  gainNode.connect(panNode);
  panNode.connect(compressor)
  
  let freq = quantize(scale, 440 * (Math.random() * 3))
  
  oscillator.frequency.setValueAtTime(
    quantize(scale, freq),
    audioCtx.currentTime,
  )
  
  // Low pass gate 
  biquadFilter.frequency.setValueAtTime(
    quantize(scale, freq * 4), 
    audioCtx.currentTime
  );
  
  biquadFilter.frequency.setTargetAtTime(
    freq, 
    audioCtx.currentTime,
    0.09,
  );  
  
  // accend the low pass gate with normal attenuatiob
  gainNode.gain.setValueAtTime(
    gain, 
    audioCtx.currentTime
  );    
  
  gainNode.gain.setTargetAtTime(
    0, 
    audioCtx.currentTime,
    0.1,
  );  

  // random stereo pan
  panNode.pan.setValueAtTime(
    Math.random() * 2 - 1, 
    audioCtx.currentTime
  );
  
  oscillator.start()
  oscillator.stop(audioCtx.currentTime + 1)
}

async function delayNote(f, time, decay, gain = 1){  
  if (gain <= 0) {
    return // stop repeats when they become inaudible
  }
  
  f(gain)
  
  setTimeout( _ => delayNote(f, time, decay, gain - decay), time);
}

observer.observe(document, {
  attributes: true,
  childList: true,
  subtree: true,
  characterData: true,
})  
@luigimannoni

This comment has been minimized.

Copy link

@luigimannoni luigimannoni commented Feb 19, 2020

Deploy this on production but use an Arnold Schwarzenegger sound bank which plays a random line at each DOM mutation.

@albertodeago

This comment has been minimized.

Copy link

@albertodeago albertodeago commented Feb 19, 2020

Wow this is probably the best gist I've ever seen

@dodds-cc

This comment has been minimized.

Copy link

@dodds-cc dodds-cc commented Feb 19, 2020

love this

@nanxiaobei

This comment has been minimized.

Copy link

@nanxiaobei nanxiaobei commented Feb 19, 2020

Added quantization and randomness + delay for a cuter effect πŸ˜‡

https://gist.github.com/MarkArts/3d4217f957df8a30802a8cbf962fa204

// origin: https://gist.github.com/tomhicks/6cb5e827723c4eaef638bf9f7686d2d8 ,  tomhicks/plink-plonk.js

/*
Copy this into the console of any web page that is interactive and doesn't
do hard reloads. You will hear your DOM changes as different pitches of
audio.
I have found this interesting for debugging, but also fun to hear web pages
render like UIs do in movies.
*/

// dorian (-)   C     E      F     G-     A     B-   
let scale = [
  264, 330, 352, 391.1, 440, 488.9 
]
scale = scale.concat(scale.map(x=>x*2))

console.log(scale)

function quantize(scale, freq) {
  return scale.reduce(function(prev, curr){
    return (Math.abs(curr - freq) < Math.abs(prev - freq) ? curr : prev);
  });
}

const audioCtx = new (window.AudioContext || window.webkitAudioContext)()
const observer = new MutationObserver(observe)

function observe(mutationsList) {
  // with delay
  delayNote(gain => playNote(mutationsList, gain), 300, 0.2)  
  // without
  // playNote(mutationsList)
}


// Compressor as final stage to prevent clipping
const compressor = audioCtx.createDynamicsCompressor()
compressor.threshold.setValueAtTime(-40, audioCtx.currentTime);
compressor.knee.setValueAtTime(40, audioCtx.currentTime);
compressor.ratio.setValueAtTime(12, audioCtx.currentTime);
compressor.attack.setValueAtTime(0, audioCtx.currentTime);
compressor.release.setValueAtTime(0.25, audioCtx.currentTime);
compressor.connect(audioCtx.destination)

async function playNote(mutationsList, gain = 1) {  
  audioCtx.resume()
  
  const oscillator = audioCtx.createOscillator()
  oscillator.type = "triangle"
  const biquadFilter = audioCtx.createBiquadFilter();
  biquadFilter.type = "lowpass";
  const gainNode = audioCtx.createGain();
  const panNode = audioCtx.createStereoPanner();  
  
  // Setup audio chain 
  oscillator.connect(biquadFilter);
  biquadFilter.connect(gainNode);
  gainNode.connect(panNode);
  panNode.connect(compressor)
  
  let freq = quantize(scale, 440 * (Math.random() * 3))
  
  oscillator.frequency.setValueAtTime(
    quantize(scale, freq),
    audioCtx.currentTime,
  )
  
  // Low pass gate 
  biquadFilter.frequency.setValueAtTime(
    quantize(scale, freq * 4), 
    audioCtx.currentTime
  );
  
  biquadFilter.frequency.setTargetAtTime(
    freq, 
    audioCtx.currentTime,
    0.09,
  );  
  
  // accend the low pass gate with normal attenuatiob
  gainNode.gain.setValueAtTime(
    gain, 
    audioCtx.currentTime
  );    
  
  gainNode.gain.setTargetAtTime(
    0, 
    audioCtx.currentTime,
    0.1,
  );  

  // random stereo pan
  panNode.pan.setValueAtTime(
    Math.random() * 2 - 1, 
    audioCtx.currentTime
  );
  
  oscillator.start()
  oscillator.stop(audioCtx.currentTime + 1)
}

async function delayNote(f, time, decay, gain = 1){  
  if (gain <= 0) {
    return // stop repeats when they become inaudible
  }
  
  f(gain)
  
  setTimeout( _ => delayNote(f, time, decay, gain - decay), time);
}

observer.observe(document, {
  attributes: true,
  childList: true,
  subtree: true,
  characterData: true,
})  

This one's great~ πŸ˜‡

@everaldo

This comment has been minimized.

Copy link

@everaldo everaldo commented Feb 19, 2020

Awesome idea!

It would be nice to create some debugging library with sounds for Ajax Requests, Ajax failures, console errors etc.

@R4meau

This comment has been minimized.

Copy link

@R4meau R4meau commented Feb 19, 2020

@everaldo I'm working on it at the moment: https://github.com/r4meau/plink-plonk

Also, great idea about the console errors. Added this to the list of features in the README :). For the requests, it's already in the list.

@everaldo

This comment has been minimized.

Copy link

@everaldo everaldo commented Feb 19, 2020

@R4meau, that's awesome!

@Adrinalin4ik

This comment has been minimized.

Copy link

@Adrinalin4ik Adrinalin4ik commented Feb 20, 2020

Maybe someone makes some chrome extension?

@AlexRatmansky

This comment has been minimized.

Copy link

@AlexRatmansky AlexRatmansky commented Feb 20, 2020

And the bookmarklet version:

javascript:(function(){const%20audioCtx=new(window.AudioContext||window.webkitAudioContext);const%20oscillator=audioCtx.createOscillator();oscillator.connect(audioCtx.destination);oscillator.type="sine";let%20numItems=0;oscillator.frequency.setValueAtTime(1,audioCtx.currentTime);oscillator.start();const%20observer=new%20MutationObserver(function(mutationsList){numItems+=mutationsList.length;oscillator.frequency.setValueAtTime(Math.log(numItems+1)*440,audioCtx.currentTime);setTimeout(()=>{numItems-=mutationsList.length;if(numItems===0){oscillator.frequency.setValueAtTime(1,audioCtx.currentTime)}else{oscillator.frequency.setValueAtTime(Math.log(numItems+1)*440,audioCtx.currentTime)}},100)});observer.observe(document,{attributes:true,childList:true,subtree:true,characterData:true})})();
@aibolik

This comment has been minimized.

Copy link

@aibolik aibolik commented Feb 21, 2020

Maybe someone makes some chrome extension?

Yeah, let's do it... (adding to backlog) πŸ˜…

@R4meau

This comment has been minimized.

Copy link

@R4meau R4meau commented Feb 21, 2020

@aibolik Already in the making: https://github.com/r4meau/plink-plonk

Feel free to fork and contribute... or start your own. πŸ˜„

I'm gonna go slow on it for now (Sunday only), but I'll accept useful PRs at anytime.

@mahnouel

This comment has been minimized.

Copy link

@mahnouel mahnouel commented Feb 28, 2020

Could anyone add reload support? This is so wonderful πŸ₯° Maybe via localStorage? Or as Firefox Extension?

@iamnmanoj

This comment has been minimized.

Copy link

@iamnmanoj iamnmanoj commented Mar 4, 2020

Its so helpful to find out the DOM manipulations happening behind the eyes!!. Good job @R4meau

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.