Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.min.js"></script>    
  <div id="overlay">
    <p>Play</p>
  </div>
  <div class="link">
    <a href="https://soundcloud.com/ma-suwa/chorus_a-vy1" target="_blank">music by masuwa</a>
  </div>
  
  <div id="myCanvas"></div>



  <script id="fragmentShader" type="x-shader/x-fragment">
    varying vec2 vUv;
    uniform vec2 u_resolution;
    uniform float u_time;
    uniform vec2 u_mouse;
    uniform float u_radius;
    uniform float u_scrollY;

    uniform float u_volume;//光の強さ

    uniform sampler2D uTex;

    float random (in float x) {
      return fract(sin(x)*1e4);
    }
    float random (vec2 st) {
      return fract(sin(dot(st.xy,
                            vec2(12.9898,78.233)))*
          43758.5453123);
    }
    

    void main() {
      /************************/
      //画像解像度 (縦横が2の累乗サイズ推奨)
      //https://qiita.com/watabo_shi/items/2fc671f2147e799787f9
      /************************/
      vec2 imageResolution = vec2(1024.0, 1024.0);

      /************************/
      //windowサイズいっぱいに広げたPlaneのテクスチャにbackground-size:coverのような挙動をさせる。
      //https://qiita.com/ykob/items/4ede3cb11684c8a403f8 
      /************************/
      vec2 ratio = vec2(
        min((u_resolution.x / u_resolution.y) / (imageResolution.x / imageResolution.y), 1.0),
        min((u_resolution.y / u_resolution.x) / (imageResolution.y / imageResolution.x), 1.0)
      );
      vec2 uv = vec2(
          vUv.x * ratio.x + (1.0 - ratio.x) * 0.5,
          vUv.y * ratio.y + (1.0 - ratio.y) * 0.5
      );

      float d = dot(uv,uv);
      float a = atan(uv.y,uv.x);

      float aspect = u_resolution.x / u_resolution.y;

      vec2 center = vec2( u_mouse.x, u_mouse.y );// アスペクト補正したマウス座標
      float radius = u_volume+(center.x+center.y)*0.001;
      float r =  u_volume+(center.x+center.y)*(0.5+u_volume);
      float lightness = radius / length( uv - center );
      vec3 light = vec3(0.0);
      for(int j = 0; j < 3; j++){
        for(int i=0; i < 5; i++){
          light[j] += radius / abs(fract(float(r) - float(j*j)*0.01) - length(uv - center) + random(uv+u_time)*u_volume*2.0);
        }
      }
      vec3 color = vec3(random(uv*u_time*d)*0.2, -uv.x*uv.y*d, uv.x*uv.y);      
      //vec3 color = texture2D( uTex, uv).rgb;       
      gl_FragColor = vec4( color+light, 1.0 );
    }
  </script>
  
  <script id="vertexShader" type="x-shader/x-vertex">  
    varying vec2 vUv;
    void main() {
      vUv = uv;// uv: ShaderMaterialで補完される vec2 型(xy)の変数。テクスチャ座標のこと。
      gl_Position = vec4( position, 1.0 );
    }
  </script>


              
            
!

CSS

              
                * {
    margin: 0;
    padding: 0;
  }
  
  html {
    height: 100%;
    background-color: #FFF; 
  }
  
  body {  
    margin: 0;
    height: 100%;
    font-family: 'Noto Sans JP', sans-serif;
    height: 10000px;
  }

  #myCanvas {
    overflow: hidden;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;  
  }
  #myCanvas canvas {  
    display: block;
    width: 100%;
    height: 100%;
  }

  #overlay {
    position: absolute;
    z-index: 1;
    top: 0;
    left: 0;
    width: 100%;
    height:100%;
    display: none;
    align-items: center;
    justify-content: center;
    opacity: 1;
    background-color: #000000;
    color: #ffffff;
  }

  p{
    color: #ffffff;
  }

  .link{
    color: #000;
    background: #FFF;
    mix-blend-mode: exclusion;
  font-size: 12px;
  position: absolute;
  left: 10px;
  bottom: 10px;
  }

  .link a{
    text-decoration: underline;
    font-size: 10px;
      color: #000;

  }
              
            
!

JS

              
                class Audio {
  constructor(soundUrl){

      this.listener = new THREE.AudioListener();
      const audio = new THREE.Audio( this.listener );
      this.xhr = 0;
      
      this.audioLoader = new THREE.AudioLoader();
      this.audioLoader.load( soundUrl, 
          function( buffer ) {
              audio.setBuffer( buffer );
              audio.setLoop( true );
              audio.setVolume( 1.0 );
          },
          // onProgress callback
          function ( xhr ) {
              if (xhr.loaded / xhr.total * 100 === 100) {
                  setTimeout(() => {
                      document.getElementById( 'overlay' ).style.display = "block";
                  }, 1000)
              }else{}
          },
          // onError callback
          function ( err ) {
              console.log( 'An error happened' );
          }
      );
      this.soundPlay = () => {
          audio.play();
      }
      this.analyser = [];
      this.analyser = new THREE.AudioAnalyser( audio, 256 );
  }

  update(){
      this.FrequencyData = this.analyser.getFrequencyData();
      this.AverageFrequency = this.analyser.getAverageFrequency();
  }
  
}


class Canvas {
  constructor() {
    /************************/
    /*インタラクション用*/
    /************************/

    //スクロール量
    this.scrollY = 0;
    //マウス座標
    this.mouse = new THREE.Vector2(0.5, 0.5);
    this.targetRadius = 0.05;// 半径の目標値
    //ウィンドウサイズ
    this.w = window.innerWidth;
    this.h = window.innerHeight;


    /************************/
    /*シーン設定*/
    /************************/

    // レンダラー
    this.renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    this.renderer.setSize(this.w, this.h);// 描画サイズ
    this.renderer.setPixelRatio(window.devicePixelRatio);// ピクセル比
    this.renderer.setClearColor( 0xEEEEEE );

    //#myCanvasにレンダラーのcanvasを追加
    const container = document.getElementById("myCanvas");
    container.appendChild(this.renderer.domElement);

    // カメラ
    /*js上の数値をpixelに変換する処理*/
    const fov    = 60;
    const fovRad = (fov / 2) * (Math.PI / 180);// 視野角をラジアンに変換
    const dist   = (this.h / 2) / Math.tan(fovRad);// ウィンドウぴったりのカメラ距離
    /* */
    this.camera = new THREE.PerspectiveCamera(fov, this.w / this.h, 1, dist * 2);
    this.camera.position.z = dist;// カメラを遠ざける
    

    // シーン
    this.scene = new THREE.Scene();
    this.scene.fog = new THREE.Fog(0xCCCCCC, 0, 2000);

    // ライト
    this.pointLight = new THREE.PointLight(0xffffff);
    this.pointLight.position.set(40, 40, 0);// ライトの位置を設定
    this.scene.add(this.pointLight);

    this.ambientLight = new THREE.AmbientLight(0xFFFFFF, 0.9);
    this.scene.add(this.ambientLight);


    /************************/
    /*オブジェクト*/
    /************************/

    const loader = new THREE.TextureLoader();// テクスチャローダーを作成
    this.texture = loader.load('https://picsum.photos/id/31/1024/1024');// テクスチャ読み込み

   
    // 平面をつくる(幅, 高さ, 横分割数, 縦分割数)
    const plane = new THREE.PlaneGeometry(2, 2, 10, 10);
    // シェーダーソースを渡してマテリアルを作成
    this.uniforms = {
      "u_time": { value: 1.0 },
      "u_resolution": { type: "v2", value: new THREE.Vector2(this.renderer.domElement.width,this.renderer.domElement.height) },
      "u_mouse": {value: new THREE.Vector2(0.5, 0.5)},
      "u_scrollY": {value: 0.0},
      "u_radius": {value: this.targetRadius},
      "uTex": {value: this.texture},
      "u_volume" : {value: 0.0}
    };
    const plane_mat = new THREE.ShaderMaterial({
      uniforms: this.uniforms,
      vertexShader: document.getElementById( 'vertexShader' ).textContent,
      fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
      wireframe: false
    });
    this.plane = new THREE.Mesh(plane, plane_mat);
    this.scene.add(this.plane);

      

      

    /************************/
    /*画面更新*/
    /************************/

    this.renderer.render(this.scene, this.camera);


    const overlay = document.getElementById( 'overlay' );
    const url = 'https://dl.dropbox.com/s/c6sou8pfw168mgg/sound.m4a?dl=0';
    this.audio1 = new Audio(url);
    overlay.addEventListener('click', e => {
        overlay.remove();
        this.audio1.soundPlay();
        this.render();
    });
 
  }

  render() {

    requestAnimationFrame(() => { this.render(); });
    
    // ミリ秒から秒に変換
    const sec = performance.now() / 1000;
    this.plane.material.uniforms.u_time.value += 1;
    // シェーダーを更新
    this.uniforms.u_mouse.value.lerp(this.mouse, 0.05);
    //this.uniforms.u_scrollY.value = this.scrollY;
    this.audio1.update();
   
    this.uniforms.u_volume.value = this.audio1.AverageFrequency*0.0003;
    //AverageFrequency
    // this.uniforms.u_radius.value += (this.targetRadius - this.uniforms.u_radius.value) * 0.01;
    // 画面に表示

    this.renderer.render(this.scene, this.camera);
    
  }

  mouseMoved(x, y) {
    this.mouse.x =  x / this.w;// 原点を中心に持ってくる
    this.mouse.y = 1.0 - (y / this.h);// 軸を反転して原点を中心に持ってくる
  }

  scrolled(y) {
    this.scrollY = y;        
  }

  resized() {
    this.w = window.innerWidth;
    this.h = window.innerHeight;
    this.renderer.setSize(this.w, this.h);
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.camera.aspect = this.w / this.h;
    this.camera.updateProjectionMatrix();
    this.uniforms.u_resolution.value = new THREE.Vector2(this.renderer.domElement.width,this.renderer.domElement.height);
  }
};

//このクラス内に ページごとのcanvas外の処理を書いていきます
window.addEventListener('DOMContentLoaded', function(){

  const canvas = new Canvas();
  canvas.scrolled(window.scrollY);

  /************************/
  /*addEventListener*/
  /************************/

  window.addEventListener('mousemove', e => {
    canvas.mouseMoved(e.clientX, e.clientY);
  });

  window.addEventListener('scroll', e => {
    canvas.scrolled(window.scrollY);
  });

  window.addEventListener('resize', e => {
    canvas.resized();
  });

});
              
            
!
999px

Console