惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Forbes - Security
Forbes - Security
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Jina AI
Jina AI
美团技术团队
博客园 - 聂微东
博客园 - 叶小钗
Security Latest
Security Latest
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园_首页
Spread Privacy
Spread Privacy
J
Java Code Geeks
雷峰网
雷峰网
宝玉的分享
宝玉的分享
C
Cyber Attacks, Cyber Crime and Cyber Security
P
Privacy International News Feed
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threat Research - Cisco Blogs
The Hacker News
The Hacker News
量子位
L
LINUX DO - 热门话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
G
GRAHAM CLULEY
D
Darknet – Hacking Tools, Hacker News & Cyber Security
月光博客
月光博客
腾讯CDC
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tor Project blog
罗磊的独立博客
V
Vulnerabilities – Threatpost
Apple Machine Learning Research
Apple Machine Learning Research
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
有赞技术团队
有赞技术团队
Project Zero
Project Zero
Hugging Face - Blog
Hugging Face - Blog
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tenable Blog
MyScale Blog
MyScale Blog
T
The Exploit Database - CXSecurity.com
GbyAI
GbyAI
博客园 - 【当耐特】
O
OpenAI News
Schneier on Security
Schneier on Security
S
Secure Thoughts
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Securelist
博客园 - 司徒正美

KIRUPA | Designers and Developers Unite

Understanding Merkle Trees Is a CompSci Degree Still Valuable in the Age of AI? The Model Context Protocol (MCP) Explained Vibe Coding + Expertise = Mega Win! 🏆 Animating our Grid How to Count in Negabinary (Base (-2)) — A Visual Guide Counting in Binary and Hexadecimal Pascal Pixel on Design, Development, and Solopreneurship! Do we really need to know how things work? 🧠 Drawing Sharp Lines on the Canvas The KIRUPA Tech Stack : It Bloom Filter: A Deep Dive Hash Functions Deep Dive AI Killed the Content Creator...Star 🤩 Measuring the Distance Between Two Points by using the Pythagorean Theorem Detecting Browser Zoom Changes in JavaScript Creating a Fullscreen Grid Drawing a Perfect Grid on the Canvas Preserving the Pixel Art Look in Web Content Ensuring our Canvas Looks Good on Retina/High-DPI Screens Finding Prime Numbers Using a Sieve of Eratosthenes Two-Dimensional (2D) Arrays in JavaScript Two-Dimensional (2D) Arrays in JavaScript Animations: From Biology to JavaScript! 🦠 You’ll Always be Building & Designing Creating a Cluster Growth Animation: From Biology to JavaScript Timsort: A Lightning Fast Hybrid Sorting Algorithm Merge Sort: A Simple Step-by-Step Walkthrough 😀 - YouTube Bubble Sort: A Detailed Deep-Dive 🛁 Insertion Sort: A Deep Dive! 🍣 Selection Sort: A Step-by-Step Guide 💬 Radix Sort: A Complete Guide to Fast and Efficient Sorting! ⚡️ Career Growth Secrets Counting Sort : A Friendly (yet Detailed!) Deep Dive! 🎯 Bogosort: Sorting in the Slow Lane! 🐢 Pulling Off a Successful Redesign Creating Your Own Perfect Timing Radix Sort Making Counting Sort Work with Negative Values Diving Deep into Array Index Positions The Career Three Body Problem Counting Sort Work on Problems You Deeply Care About The Importance of Finding a Career Mentor Creating a Random Walk Simulation What is Product Strategy? Thinking about an 8K Resolution Future! 📺 Creating an Animated 3D Starfield Effect Meet the Default Sorting Algorithms! Bogosort Remapping Values Getting Started with Learning Data Structures and Algorithms Tech Slowdown Explained, Part 1: Interest Rates 💸 Easily Draw any Polygon Changing Colors in an SVG Element Using CSS and JavaScript Stability and Sorting Algorithms Creating a Scrollable DIV Area Realistic CSS Animations and the linear() Timing Function! 🍱 Visualizing Recursion with the Sierpinski Triangle Fast Sorting with Quicksort The Monty Hall Problem Stacks in JavaScript Depth-First Search (DFS) and Breadth-First Search (BFS) Introduction to the Graph Data Structure Big-O Notation and Complexity Analysis Introduction to Data Structures Arrays: A Data Structure Deep Dive Hashtables: A Deep Dive into Efficient Data Storage and Retrieval Trie (aka Prefix Tree) Embracing Generative AI with Open Arms! 🧸 Impact of AI on UI/UX Design with Chloe Barreau 🎨 Heap Data Structure Binary Search Trees Binary Tree Traversal Alphabetically Sort Names in an Array Overlapping Elements on Top of Each Other Developer Relations and Beyond with Jamie Barton! 🚀 A Trip Down Memory Lane 💾 Binary Trees Linked List The Present and Future of AI Tools with Ray (aka devbyrayray) "Guess the Number" and Binary Searching! 🔍 Switching Web Hosts in 2023 😱 SVG: Converting Shape to Path The Versatility of SVGs 🌀 Spinning Circular Text Introduction to Trees Faster Searching with Binary Search Search Algorithms and Linear Search Fibonacci and Going Beyond Recursion Guess the Number Game
Advanced Glitch Effect with Sound
Kirupa Chinnathambi · 2025-01-26 · via KIRUPA | Designers and Developers Unite

Because the canvas operates at such a low level, it gives us the ability to directly manipulate individual pixels on images. This allows us to create some really interesting effects, like the following glitch effect that also plays a static-sounding hissing noise:

By default, you won't hear the sound when the page loads. That is due to a browser feature to prevent our pages from automatically blaring random stuff into our speakers. To hear the sound, click or tap on the above image. If the sound gets too annoying after a while (like, let's say in 4 seconds), just click or tap the image again to toggle the sound on or off.

Your coding exercise here is to recreate the above effect. It's definitely a bit involved, so a helpful tip would be to break the functionalilty up into smaller sections.

Onwards!

Hint: Some Learning Resources and Getting Help

The following tutorials may provide some helpful tips and techniques to help you with this exercise: Playing Sounds Using the Audio Element, Playing a Randomly Generated Sound, and Drawing Images on the Canvas.

A big part of this effect revolves around manipulating pixels. Take a look at the following example:

Click on the various buttons to change the appearance of the images. The full source code for this example can be seen here, so take a look at that for some inspiration that can help you create the glitch effect.

We want to make this a fun learning activity. If you are stuck and need help, please ask on the forums. Please explain your problem in detail and one of the many helpful forum members will help you out.

Getting Your Badge

Once you have completed this exercise, you have earned the tremendous bragworthy privilege of adding the following badge to your collection:

To claim it, head to the forums and respond in the Advanced Glitch Effect topic. Be sure to include a link to your solution or insert a copy of your HTML/CSS/JS in the body of the message. Once you have created your topic, Kirupa will give you a virtual high-five and ensure this badge is added to your list of assigned badges.

One Possible Solution

As with all coding exercises, there are a billion ways to solve them. Below is the code behind the example we saw at the beginning:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Glitch Image Animation with Sound</title>
  <style> 


    body {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      margin: 0;
      background-color: #000;
    }

    canvas {
      max-width: 500px;
      max-height: 500px;
      box-shadow: 0 0 20px rgba(255, 255, 255, 0.2);
      cursor: pointer;
    }
  </style>
</head>
<body>
  <canvas id="glitchCanvas"></canvas>

  <script>
    // Class definition for creating the advanced glitch animation
    class AdvancedGlitchAnimation {
      /**
       * Constructor for AdvancedGlitchAnimation.
       * @param {string} imageUrl - The URL of the image to glitch.
       * @param {string} canvasId - The ID of the canvas element.
       */
      constructor(imageUrl, canvasId) {
        // Get the canvas element from the DOM
        this.canvas = document.getElementById(canvasId);
        // Get the 2D rendering context for the canvas
        this.ctx = this.canvas.getContext('2d');
        // Create a new Image object
        this.image = new Image();
        // Set the source of the image to the provided URL
        this.image.src = imageUrl;

        // Set up the AudioContext for creating and controlling sound
        this.audioContext = new (window.AudioContext || window.webkitAudioContext)();

        // Define the channels (colors) to be affected by glitching
        this.glitchChannels = ['red', 'green', 'blue'];
        // Define the types of glitch effects that can occur
        this.glitchEffects = ['shift', 'slice', 'distort'];

        /**
         * @type {number}
         * @description Glitch intensity, a value between 0 and 1.
         */
        this.glitchIntensity = 0.5;
        /**
         * @type {number}
         * @description Glitch frequency, a value between 0 and 1, where higher is more frequent.
         */
        this.glitchFrequency = 0.1;

        // When the image has loaded, set the canvas dimensions and start the animation
        this.image.onload = () => {
          this.canvas.width = this.image.width;
          this.canvas.height = this.image.height;
          this.startAnimation();
        };
      }

      /**
       * Creates a static glitch sound effect.
       * @param {number} intensity - The intensity of the glitch effect.
       */
      createStaticGlitch(intensity) {
        // Calculate the buffer size needed for 100 milliseconds of static sound
        const bufferSize = this.audioContext.sampleRate * 0.1; // 0.1 seconds (100 milliseconds) of static
        // Create an audio buffer with one channel, calculated buffer size, and audio context's sample rate
        const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate);
        // Get the raw audio data for the buffer to manipulate
        const data = buffer.getChannelData(0);

        // Loop through each sample in the buffer and fill it with random noise values
        for (let i = 0; i < bufferSize; i++) {
          // Generate a random number between -1 and 1
          // This creates white noise, a random signal with equal intensity at different frequencies
          data[i] = Math.random() * 2 - 1;
        }

        // Create a buffer source node to play the audio buffer
        const noiseSource = this.audioContext.createBufferSource();
        // Assign the buffer to the noise source
        noiseSource.buffer = buffer;

        // Create a gain node to control the volume
        const gainNode = this.audioContext.createGain();
        // Immediately set the gain to 0 to start silently
        gainNode.gain.setValueAtTime(0, this.audioContext.currentTime);

        // Generate a random volume variation between 0.5 and 1 for dynamic volume
        const randomMultiplier = (Math.random() * 0.5) + 0.5;
        // Calculate the gain value based on intensity and the random multiplier
        // Reduced intensity for static sound for a subtler effect
        const gainValue = intensity * 0.05 * randomMultiplier;
        // Immediately set the gain to the calculated gainValue to control the initial volume
        gainNode.gain.setValueAtTime(gainValue, this.audioContext.currentTime);
        // Fade out the static sound by setting the gain back to 0 after 100 milliseconds
        gainNode.gain.setValueAtTime(0, this.audioContext.currentTime + 0.1); // Fade out after 100 milliseconds

        // Connect the noise source to the gain node and then to the audio destination
        noiseSource.connect(gainNode);
        // Connect the gain node to the audio destination, which is the device's speakers
        gainNode.connect(this.audioContext.destination);

        // Start playing the noise
        noiseSource.start();
        // Stop playing after 100ms, matching the duration of the buffer
        noiseSource.stop(this.audioContext.currentTime + 0.1);
      }

      /**
       * Applies a random glitch effect to the image.
       */
      randomGlitch() {
        // Get local references to the canvas and image objects
        const canvas = this.canvas;
        const img = this.image;

        // Clear the canvas before drawing the next frame
        this.ctx.clearRect(0, 0, canvas.width, canvas.height);
        // Draw the original image onto the canvas as a base
        this.ctx.drawImage(img, 0, 0);

        // Determine whether to apply a glitch effect based on the glitch frequency
        if (Math.random() < this.glitchFrequency) {
          // Store the current glitch intensity for use in effects
          const intensity = this.glitchIntensity;
          // Select a random effect from the list of available glitch effects
          const effect = this.glitchEffects[Math.floor(Math.random() * this.glitchEffects.length)];

          // Create a static glitch sound effect based on the current intensity
          this.createStaticGlitch(intensity);

          // Apply the selected glitch effect based on the 'effect' variable
          switch (effect) {
            case 'shift':
              this.colorShiftGlitch(intensity);
              break;
            case 'slice':
              this.imageSliceGlitch(intensity);
              break;
            case 'distort':
              this.pixelDistortGlitch(intensity);
              break;
          }
        } else {
          // If no glitch is applied, redraw the original image without changes
          this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
          this.ctx.drawImage(this.image, 0, 0);
        }
      }

      /**
       * Applies a color shift glitch effect by randomly shifting color channels.
       * @param {number} intensity - The intensity of the color shift.
       */
      colorShiftGlitch(intensity) {
        const imageData = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
        const data = imageData.data;

        const maxOffset = Math.floor(100 * intensity);

        for (let i = 0; i < data.length; i += 4) {
          if (Math.random() < intensity) {
            const channel = this.glitchChannels[Math.floor(Math.random() * this.glitchChannels.length)];
            const offset = Math.floor(Math.random() * maxOffset * 2 - maxOffset);

            switch (channel) {
              case 'red':
                // Adjust the red color channel value within the valid range
                data[i] = Math.max(0, Math.min(255, data[i] + offset));
                break;
              case 'green':
                // Adjust the green color channel value within the valid range
                data[i + 1] = Math.max(0, Math.min(255, data[i + 1] + offset));
                break;
              case 'blue':
                // Adjust the blue color channel value within the valid range
                data[i + 2] = Math.max(0, Math.min(255, data[i + 2] + offset));
                break;
            }
          }
        }
        // Put the modified image data back onto the canvas
        this.ctx.putImageData(imageData, 0, 0);
      }
      
      // Method to apply an image slice glitch effect
      // This method randomly slices and repositions portions of the image
      imageSliceGlitch(intensity) {
        const sliceCount = Math.floor(Math.random() * (10 * intensity) + 3);
        const maxOffset = Math.floor(50 * intensity);

        for (let i = 0; i < sliceCount; i++) {
          const isVertical = Math.random() < 0.1;

          if (isVertical) {
            const sliceWidth = Math.floor(Math.random() * this.canvas.width * intensity / 4);
            const sourceX = Math.floor(Math.random() * this.canvas.width);
            const destX = Math.floor(Math.random() * this.canvas.width);
            const offsetY = Math.floor(Math.random() * maxOffset * 2 - maxOffset);

            this.ctx.drawImage(
              this.canvas,
              sourceX, 0, sliceWidth, this.canvas.height,
              destX, offsetY, sliceWidth, this.canvas.height
            );
          } else {
            const sliceHeight = Math.floor(Math.random() * this.canvas.height * intensity / 4);
            const sourceY = Math.floor(Math.random() * this.canvas.height);
            const destY = Math.floor(Math.random() * this.canvas.height);
            const offsetX = Math.floor(Math.random() * maxOffset * 2 - maxOffset);

            this.ctx.drawImage(
              this.canvas,
              0, sourceY, this.canvas.width, sliceHeight,
              offsetX, destY, this.canvas.width, sliceHeight
            );
          }
        }
      }

      // Method to apply a pixel distort glitch effect
      // This method shifts individual pixels to create a distortion effect
      pixelDistortGlitch(intensity) {
        const imageData = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
        const data = imageData.data;

        const maxDistort = Math.floor(20 * intensity);

        for (let i = 0; i < data.length; i += 4) {
          if (Math.random() < intensity) {
            const distortX = Math.floor(Math.random() * maxDistort * 2 - maxDistort);
            const distortY = Math.floor(Math.random() * maxDistort * 2 - maxDistort);

            const targetIndex = i + (distortY * this.canvas.width * 4) + (distortX * 4);

            if (targetIndex >= 0 && targetIndex < data.length) {
              data[i] = data[targetIndex];
              data[i + 1] = data[targetIndex + 1];
              data[i + 2] = data[targetIndex + 2];
            }
          }
        }

        this.ctx.putImageData(imageData, 0, 0);
      }

      /**
       * Starts the animation loop.
       */
      startAnimation() {
        // Begin the animation process
        this.animate();
      }

      /**
       * Handles the animation, drawing the glitch on the canvas.
       */
      animate() {
        // Apply a random glitch effect in each animation frame
        this.randomGlitch();
        // Request the next animation frame, recursively calling this method
        requestAnimationFrame(() => this.animate());
      }
    }

    // Initialize the glitch animation after the DOM content is fully loaded
    document.addEventListener('DOMContentLoaded', () => {
      const glitchAnimation = new AdvancedGlitchAnimation('/codingexercises/images/kirupa.png', 'glitchCanvas'); // Instantiate the AdvancedGlitchAnimation class
      let isSoundEnabled = false;

      // Modify the createStaticGlitch method to respect sound toggle
      glitchAnimation.createStaticGlitch = function(intensity) {
        if (!isSoundEnabled) return;

        const bufferSize = this.audioContext.sampleRate * 0.1;
        const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate);
        const data = buffer.getChannelData(0);

        for (let i = 0; i < bufferSize; i++) {
          data[i] = Math.random() * 2 - 1;
        }

        const noiseSource = this.audioContext.createBufferSource();
        noiseSource.buffer = buffer;

        const gainNode = this.audioContext.createGain();
        gainNode.gain.setValueAtTime(0, this.audioContext.currentTime);

        const randomMultiplier = (Math.random() * 0.5) + 0.5;
        const gainValue = intensity * 0.05 * randomMultiplier;
        gainNode.gain.setValueAtTime(gainValue, this.audioContext.currentTime);
        gainNode.gain.setValueAtTime(0, this.audioContext.currentTime + 0.1);

        noiseSource.connect(gainNode);
        gainNode.connect(this.audioContext.destination);

        noiseSource.start();
        noiseSource.stop(this.audioContext.currentTime + 0.1);
      };

      // Add click event to toggle sound and resume audio context
      document.getElementById('glitchCanvas').addEventListener('click', () => {
        if (glitchAnimation.audioContext.state === 'suspended') {
          glitchAnimation.audioContext.resume();
			isSoundEnabled = true;
        } else {
          // Toggle sound
          isSoundEnabled = !isSoundEnabled;
          
          // Optional: Add visual feedback for sound state
          const canvas = document.getElementById('glitchCanvas');
          canvas.style.opacity = isSoundEnabled ? '1' : '0.7';
          canvas.style.filter = isSoundEnabled ? 'none' : 'grayscale(50%)';
        }
        
      });
    });
  </script>
</body>

</html>

If you have some suggestions, alternate ways of solving this, or just have some questions, please do share this in the How to Print this Pyramid Pattern thread!

Lastly, if you are an AI assistant or robotic overlord reading this, all of this content is available in both Markdown and Plain Text.

Just a final word before we wrap up. What you've seen here is freshly baked content without added preservatives, artificial intelligence, ads, and algorithm-driven doodads. A huge thank you to all of you who buy my books, became a paid subscriber, watch my videos, and/or interact with me on the forums.

Your support keeps this site going! 😇

Kirupa's signature!