戻る
2023/07/15

3D Kirico cube プログラムノート


[実行サンプル・最新版](click)
*江戸切子、薩摩切子をイメージしKirico Cubeと名付けた。


最初に

新型コロナウィルスのため在宅機会が多くなって、ウェブブラウザで3Dオブジェクトを表現するJavaScriptで作られたThree.jsライブラリーを使ってみようと思い立った。

当初は撮りためた写真とbgmを合わせたスライドを作るのが目的だったが、その後3Dオブジェクトをオーデイオに合わせてみようと思い、写真スライド版と音楽を目でも楽しむaudio visualizer バージョンの2本立てとなった。
それまでJavaScriptはウェブブラウザ記事の補助的な意味で使っていた。

久しぶりに最新の作品を整理しておく。

趣味でオブジェクトをウェブブラウザ上で表現すると、オブジェクト数が多いほど見栄えがよいと思い、比較的簡単に大量定義できる手法を物色していた。

出会ったのがこちらのサイト「ICS MEDIAWebGL と JavaScript で学ぶ3D表現Three」Three.jsについて基本編、中級編、応用編と段階を踏み分かりやすく丁寧に説明してある。

GeometryはBufferGeometryUtilsを使って定義し、最終的に一つのmeshにする。 参)BufferGeometryUtils  

そのため個々のオブジェクト毎に処理は出来ないので、audioデータを使い、cameraを移動し、spotlightの色に変化を持たせることにした。


*3D要素リマインド

  • geometry (幾何学) : 球体、直方体、平面などの形状を定義する
  • material (物質) : 物体の質感設定、着色や画像貼り付け、陰影などの見栄えを定義する
  • mesh (網) : geometryとmaterialを結合したオブジェクト、位置の情報など持ち、移動、回転などの対象
  • rendering(描画) : コンピュータプログラムによって2Dまたは3Dモデルから画像を生成するプロセス。生成された画像はrenderと呼ばれる。

  • 以下作成したhtml、css、js(JavaScript)の実コードと要点の説明(2023/07/15日現在)


    html

    
    <!DOCTYPE html>
    <html lang="ja" dir="ltr">
     <head>
     <meta charset="UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <meta name="google" content="notranslate" />
     <title>Sound Visualizer Kirico version</title>
     <link href="https://fonts.googleapis.com/css2?family=Titillium+Web:wght@200&display=swap" rel="stylesheet" />
     <link rel="stylesheet" href="css/kl.css" />
         <script type="importmap">
          {
            "imports": {
              "three": "https://unpkg.com/three@0.151.3/build/three.module.js",
              "three/addons/": "https://unpkg.com/three@0.151.3/examples/jsm/"
            }
          }
        </script>
     <script type="module" src ="js/KiricoCube2.js"> </script> 
    </head>
    <body>
    
    <div id="btn_box">
    <button id="btnStart">START</button>
    <button id="btnStop" hidden>STOP</button>
    <span id ="timer"></span>
    <span id="music_title"></span>
    </div>
    <div id="Select_box">
       <form name="form1">
        <select name="music1">
        <!-- music file % img % img width % img height -->
         <optgroup label="Top Sound"> 
          <option value="../music/Debbusy-Reverie.mp3%../adimg/eine2.jpg%1200%900">Debbusy - 夢</option>
         </optgroup>
         <optgroup label="Special Sound"> 
          <option value="../music/Beethoven-Symphony-No9-4th-An-die-Freuode.mp3%../adimg/happy_arcadia.jpg%700%700%sphere">Beethoven - 交響曲第9番 ニ短調 Op.125 「合唱」 第4楽章「歓喜の歌」</option>
          <option value="../music/Mascagni-Cavalleria-Rusticana-Intermezzo.mp3%../adimg/l_083.png%500%100%sphere">Mascagni - 歌劇《カヴァレリア・ルスティカーナ》間奏曲</option>
          <option value="../music/Albinoni's Adagio in G minor.mp3%../adimg/luai_01.jpg%800%800">Albinoni - アダージョ</option>
          <option value="../music2/Songs From A Secret Garden.mp3%../adimg/Secret-Garden2.jpg%1200%800">Songs From A Secret Garden</option>
          <option value="../music2/You Raise Me Up.mp3%../adimg/celiticwomen.jpg%600%450%sphere">You Raise Me Up</option>
         </optgroup>
          <optgroup label="Selected Sound">  
          <option value="../music/Albeniz-Suite-Espanola-Granada.mp3%../adimg/guitar3.jpg%1240%827">Albeniz - グラナダ</option>
          <option value="../music/J.S.Bach-Air-On-G.mp3%../adimg/airgstring.jpg%1348%900">Bach - G線上のアリア </option>
          <option value="../music/J.S.Bach-Herz-und-Mund-und-Tat-und-Leben.mp3%../adimg/mariaandbabyjesus_00108484.jpg%1200%1000">Bach - 心と口と行いと生活で </option>
          <option value="../music/Beethoven-FurElise.mp3%../adimg/Beethoven_05.jpg%1000%1000">Beethoven - エリーゼのために</option>
          <option value="../music/Badarzewska-TheMaidens-Prayer.mp3%../adimg/piano_01.jpg%1600%1360">Bądarzewska - 乙女の祈り</option>
          <option value="../music/Beethoven-MoonlightSonata-1.mp3%../adimg/moonlight.jpg%1000%1000">Beethoven - 月光</option>
          <option value="../music/Bizet-Carmen-Air-de-Toreador.mp3%../adimg/matador01.jpg%1480%830">Bizet - 歌劇《カルメン》から 第2幕「闘牛士の歌」</option>
          <option value="../music/Bizet-LArlesienne-Menuett.mp3%../adimg/flute.jpg%1200%800">Bizet - 組曲《アルルの女》 第2番から 「メヌエット」</option>
          <option value="../music/Boccherini-Minuetto.mp3%../adimg/imusici.jpg%1500%1500">Boccherini:弦楽五重奏曲 ホ長調 G.275 第3楽章 「メヌエット」</option>  
          <option value="../music/Chopin-Etude No.3 In E Major Op .10 No.3.mp3%../adimg/piano_05.jpg%1420%830">Chopin - 別れの曲</option>
          <option value="../music/Chopin-Etude-No13-Aeolian-Harp.mp3%../adimg/aeolianharp.jpg%1420%830">Chopin - エチュード 13番「エオリアンハープ」</option>
          <option value="../music/Chopin-Etude-No23-WinterWind.mp3%../adimg/piano_05.jpg%1420%830">Chopin - 木枯らし</option>
          <option value="../music/Chopin-Fantaisie-Impromptu.mp3%../adimg/piano_05.jpg%1420%830">Chopin - 幻想即興曲</option>
          <option value="../music/Chopin-Mazurka-No13.mp3%../adimg/piano_05.jpg%1420%830">Chopin - マズルカ 第13番 イ短調 Op.17-4</option>
          <option value="../music/Chopin-MimuteWaltz.mp3%../adimg/dog14.jpg%1440%1100">Chopin - 子犬のワルツ</option>
          <option value="../music/Chopin-Nocturne-No1.mp3%../adimg/piano_07.jpg%1420%830">Chopin - Nocturne-No1</option>
          <option value="../music/Chopin-Nocturne-No2.mp3%../adimg/piano_07.jpg%1420%830">Chopin - Nocturne-No2</option>
          <option value="../music/Chopin-Nocturne-No5.mp3%../adimg/piano_07.jpg%1420%830">Chopin - Nocturne-No5</option>
          <option value="../music/Chopin-Nocturne-No8.mp3%../adimg/piano_07.jpg%1420%830">Chopin - Nocturne-No8</option>
          <option value="../music/Chopin-Nocturne-No13.mp3%../adimg/piano_07.jpg%1420%830">Chopin - Nocturne-No13</option>
          <option value="../music/Chopin-Nocturn-No15.mp3%../adimg/piano_07.jpg%1420%830">Chopin - Nocturne-No15</option>
          <option value="../music/Chopin-Nocturne-19.mp3%../adimg/chopin_19_01.jpg%1600%1600">Chopin - Nocturne-No19</option>
          <option value="../music/Chopin-Nocturne-20.mp3%../adimg/chopin_ai1.jpg%1600%1600">Chopin - Nocturne-No20</option>
          <option value="../music/Chopin-Poronase-No6-Heroic.mp3%../adimg/piano_05.jpg%1420%830">Chopin - ポロネーズ 第6番 変イ長調 「英雄」</option>
          <option value="../music/Chopin-WaltzNo1-Op.18.mp3%../adimg/piano_05.jpg%1420%830">Chopin - 華麗なる大円舞曲</option>
          <option value="../music/Chopin-Spring-Waltz.mp3%../adimg/piano_05.jpg%1420%830">Chopin - 春のワルツ</option>
          <option value="../music/Debussy-Girl-with-Flaxen-Hair.mp3%../adimg/amairo.png%900%700">Debbusy - 亜麻色の髪の乙女</option>
          <option value="../music/Debussy-The-sea-1-From-dawn-to-midday-on-the-sea.mp3%../adimg/Debussy.jpg%1024%580">Debbusy - 交響詩《海》 1. 海の夜明けから正午まで </option>
          <option value="../music/Debussy-Suite-Bergamasque-Clair-de-Lune.mp3%../adimg/tsukinohikari.jpg%1280%720">Debbusy - 《ベルガマスク組曲》より 3. 月の光 </option>
          <option value="../music/Dvorak-Humoresque.mp3%../adimg/train_sunset.jpg%1200%634">Dvorak - ユーモレスク</option>
          <option value="../music/Dvorak-Strings-Serenade-1st.mp3%../adimg/Cesky_Castle.jpg%1200%960">Dvorak - 弦楽セレナーデ ホ長調 Op.22 第1楽章</option>
          <option value="../music/Elgar-Salut-damour.mp3%../adimg/cello.jpg%1024%672">Elgar - 愛のあいさつ Op.12 (Cello) </option>
          <option value="../music/Faure-Sicilienne-Piano.mp3%../adimg/piano.jpg%1024%672">Faure - シシリエンヌ Op.78 [ピアノ版]</option>
          <option value="../music/Foster-My-Old-Kentucky-Home.mp3%../adimg/kentuckyhome.jpg%1382%1035">Foster - ケンタッキーの我が家</option>
          <option value="../music/Gershwin-Someone-to-Watch-Over-Me.mp3%../adimg/piano_01.jpg%1200%1018">Gershwin - 誰かが私を見つめてる</option>
          <option value="../music/Gounod-AveMaria.mp3%../adimg/AveMaria.jpg%600%550%sphere">Gounod - アヴェ・マリア</option>
          <option value="../music/Hendel-Lascia-chio-pianga.mp3%../adimg/rinaldo_and_armida_boucher.jpg%1200%950">Hendel - 私を泣かせてください ~涙流れるままに</option>
          <option value="../music/Hendel-WaterMusic-No2-AllaHornpipe.mp3%">Hendel - 水上の音楽</option>
          <option value="../music/Holst-The-Planets-Mars.mp3%../adimg/2k_mars.jpg%600%600%sphere">Holst:組曲《惑星》から 第1曲「火星」</option>
          <option value="../music/Holst-The-Planets-Jupiter.mp3%../adimg/2k_jupiter.jpg%600%600%sphere">Holst:組曲《惑星》から「木星」</option>
          <option value="../music/Holst-The-Planets-Jupiter-Thaxted.mp3%../adimg/jupiter_ai2.jpg%1400%1400">Holst:組曲《惑星》から「木星」 [第4主題]</option>
          <option value="../music/Ivanovici-Valurile-Dunarii.mp3%../adimg/Dunarii.jpg%1920%1080">Ivanovici -ドナウ川の漣</option>
          <option value="../music/J.Strauss2-Die-Fledermaus-Overture.mp3%">Johann Strauss2 - 喜歌劇「こうもり」序曲  </option>
          <option value="../music/Johann-Strauss-2-The-Blue-Danube.mp3%../adimg/danube.jpg%1680%769">Johann Strauss2 - 美しく青きドナウ</option>
          <option value="../music/Johann-Strauss2-Fruhlingsstimmen.mp3%../adimg/Wilhelm_Gause_Hofball_in_Wien.jpg%600%600%sphere">Johann Strauss2 - 春の声</option>
          <option value="../music/Lange-Blumenlied.mp3%../adimg/piano_06.jpg%1480%830">Lange - 花の歌</option>
          <option value="../music/Liszt-La-Campanella.mp3%../adimg/lacampanella.jpg%1280%720">Liszt - ラ・カンパネラ</option>
          <option value="../music/Liszt-Liebestraum-No3.mp3%../adimg/piano_06.jpg%1480%830">Liszt - 愛の夢</option>
          <option value="../music/Liszt-Hungarian-Rhapsodies-No2.mp3%../adimg/piano_05.jpg%1420%830">Liszt - ハンガリー狂詩曲 第2番</option>
          <option value="../music/Liszt-Consolation-No3.mp3%../adimg/Consolation.jpg%1536%864">Liszt - コンソレーション 第3番</option>
          <option value="../music/Mendelssohn-Auf-Flugeln-des-Gesanges.mp3%../adimg/violinpiano.jpg%1500%1000">Mendelssohn - 歌の翼に</option>
          <option value="../music/Mendelssohn-WeddingMarch.mp3%../adimg/lohengrin.jpg%1500%1000">Mendelssohn - 結婚行進曲 </option>
          <option value="../music/Miyagi-Haru-no-Umi.mp3%../adimg/koto.jpg%1450%400">宮城道雄 - 春の海</option>
          <option value="../music/Monti-Csardas.mp3%../adimg/Csardas.jpg%1024%1024">Monti - チャールダーシュ</option>
          <option value="../music/Mozart-EineKleine-1st.mp3%../adimg/eine1.jpg%1350%900">Mozart - アイネ・クライネ・ナハトムジーク</option>
          <option value="../music/Pachelbel-Cannon.mp3%../adimg/record.png%1500%800">Pachelbel - カノン</option>
          <option value="../music/Ravel-Borelo.mp3%../adimg/flute.jpg%1280%853">Ravel - ボレロ</option>
          <option value="../music/Rachmaninov-Prelude-in-Csharp-minor.mp3%../adimg/piano_06.jpg%1480%830">Rachmaninov - 前奏曲 嬰ハ短調 作品3-2 《鐘》</option>
          <option value="../music/Rachmaninoff-Paganini-Rhapsody-18th.mp3%../adimg/piano_06.jpg%1480%830">Rachmaninov - パガニーニの主題による狂詩曲 - 第18変奏</option>
          <option value="../music/Rodrigo-Concierto de Aranjuez.mp3%../adimg/Aranjuez_02.jpg%800%800">Rodrigo - アランフェス協奏曲   第二楽章</option>
          <option value="../music/Romance-SpanishTraditional.mp3%../adimg/guitar.jpg%1530%1142">禁じられた遊び~愛のロマンス</option>
          <option value="../music/Saint-Saens-Samson-et-Dalila-Bacchanale.mp3">Saint-saens - サムソンとデリラ</option>
          <option value="../music/Sarasate-CarmenFantasy-Habanera.mp3%../adimg/flamenco.jpg%1400%900">Sarasate - カルメン幻想曲</option>
          <option value="../music/Sarasate-Zigeunerweisen.mp3%../adimg/violin2.jpg%1600%1066">Sarasate - ツィゴイネルワイゼン</option>
          <option value="../music/Satie-Gymnopedies-No1-piano.mp3%../adimg/Adagio.jpg%1000%1000">Satie - ジムノペディ(ピアノ版)</option>
          <option value="../music/Satie-Gymnopedies-No1.mp3%../adimg/Adagio.jpg%1000%1000">Satie - ジムノペディ(オーケストラ)</option>
          <option value="../music/Schubert-AveMaria.mp3%../adimg/piano_03.jpg%1280%854"">Schubert - アヴェ・マリア</option>
          <option value="../music/Schubert-Serenade.mp3%../adimg/piano_07.jpg%1536%864">Schubert - セレナーデ</option>
          <option value="../music/Schubert-PianoSonata-No16-1.mp3%../adimg/piano.jpg%1480%830">Schubert - ピアノソナタ 第16番 イ短調 D.845 第1楽章</option>
          <option value="../music/Schubert-Wiegenlied.mp3%../adimg/Schubert-Wiegenlied.jpg%1200%640">Schubert - 子守歌</option>
          <option value="../music/Schumann-Kinderszenen-Traumerei.mp3%../adimg/kinderszenen.jpg%1440%1440">Schumann - 子供の情景(トロイメライ)</option>
          <option value="../music/Schumann-Liszt-Widmung.mp3%../adimg/myrthen.jpg%1200%800">Schumann - ミルテの花</option>
          <option value="../music/Sibelius-Finlandia.mp3%../adimg/suntoryhall1.jpg%1600%700">Sibelius - フィンランディア</option>
          <option value="../music/Tarrega-Alhambra.mp3%../adimg/alhambra.jpg%1600%1000">Tarrega - アルハンブラの思い出</option>
          <option value="../music/Tchikovsky-Melodie.mp3%../adimg/violin3.png%1536%1024">Tchaikovsky - メロディ</option>
          <option value="../music/Tchaikovsky-SwanLake-act2-Seane.mp3%../adimg/swanlake5.png%1430%1180">Tchaikovsky - 白鳥の湖 第2幕 情景</option>
          <option value="../music/Tchaikovsky-Nutcracker-Pas-de-Deux-Adage.mp3%../adimg/Nutcracker.jpg%1536%864">Tchaikovsky - くるみ割り人形 第2幕第14曲 パドドゥ</option>
          <option value="../music/Tchaikovsky-Nutcracker-waltz-flowers.mp3%../adimg/walts_flower.jpg%1400%1100">Tchaikovsky - くるみ割り人形 花のワルツ</option>
          <option value="../music/Wagner-Ride of the Valkyries.mp3%../adimg/walkure.jpg%1500%700">Wagner - ワルキューレの騎行</option>
          <option value="../music/Wagner-Tannhauser-March.mp3%../adimg/tannhauser.jpg%1500%1000">Wagner-Tannhauser - 大行進曲</option>
          <option value="../music/Wagner-Tannhauser-Overture.mp3%../adimg/tannhauser.jpg%1500%1000">Wagner-Tannhauser - 序曲</option>
          <option value="../music/Wagner-Die-Meistersinger-von-Nuernberg-Vorspiel-act1.mp3%../adimg/Die Meistersinger von Nürnberg.jpg%1600%1020">Wagner - ニュルンベルクのマイスタージンガー</option>
          <option value="../music/Weber-Der-Freischutz-Overture.mp3%../adimg/madannosyasyu.jpg%1376%1032">Weber - 歌劇『魔弾の射手』より「序曲」</option>
          <option value="../music/Weber-Aufforderung-zum-Tanz.mp3%../adimg/butoh.jpg%600%600%sphere">Weber - 舞踏への勧誘</option>
        </optgroup>
    
      <optgroup label="交響曲・協奏曲など">  
          <option value="../music/Bach-Brandenburg-Concerto-No3-1st.mp3%../adimg/Brandenburg.jpg%1580%1184">Bach - ブランデンブルク協奏曲 第3番</option>
          <option value="../music/Bach-Toccata-and-Fugue.mp3%../adimg/organ2.jpg%1400%1220">Bach -トッカータとフーガ ニ短調 BWV565</option>
          <option value="../music/Beethoven-PianoConcerto-No5-1st.mp3%../adimg/piano.jpg%1480%830">Beethoven - ピアノ協奏曲 第5番 「皇帝」 第1楽章</option>
          <option value="../music/Beethoven-PianoConcertoNo5-2.mp3%../adimg/piano.jpg%1480%830">Beethoven - ピアノ協奏曲 第5番 「皇帝」 第2楽章</option>
          <option value="../music/Beethoven-PianoConcerto-No5-3rd.mp3%../adimg/piano.jpg%1480%830">Beethoven - ピアノ協奏曲 第5番 「皇帝」 第3楽章</option>
          <option value="../music/Beethoven-Piano-Sonata-No8-Pathetique-1st.mp3%../adimg/piano.jpg%1480%830">Beethoven - ピアノソナタ 第8番 ハ短調 Op.13 《悲愴》 第1楽章</option>
          <option value="../music/Beethoven-PianoSonata-No8-2nd.mp3%../adimg/piano.jpg%1480%830">Beethoven - ピアノソナタ 第8番 ハ短調 Op.13 《悲愴》 第2楽章</option>
          <option value="../music/Beethoven-Symphony-No5-1st.mp3%../adimg/Beethoven_01.jpg%1000%1000">Beethoven - 交響曲第5番「運命」第一楽章</option>
          <option value="../music/Beethoven-Symphony-No5-2nd.mp3%../adimg/Beethoven_02.jpg%1000%1000">Beethoven - 交響曲第5番「運命」第二楽章</option>
          <option value="../music/Beethoven-Symphony-No5-3rd-4th.mp3%../adimg/Beethoven_03.jpg%1000%1000">Beethoven - 交響曲第5番「運命」第三楽章</option>
          <option value="../music/Beethoven-Symphony-No5-3rd-4th.mp3%../adimg/Beethoven_04.jpg%1000%1000">Beethoven - 交響曲第5番「運命」第四楽章</option>
          <option value="../music/Beethoven-Symphony-No6-1st.mp3%../adimg/karajan.jpg%1440%810">Beethoven - 交響曲第6番「田園」 第1楽章</option>
          <option value="../music/Beethoven-Symphony-No6-2nd.mp3%../adimg/karajan.jpg%1440%810">Beethoven - 交響曲第6番「田園」 第2楽章</option>
          <option value="../music/Beethoven-Symphony-No6-3rd-4th-5th.mp3%../adimg/karajan.jpg%1440%810">Beethoven - 交響曲第6番「田園」第3,4,5楽章</option>  
          <option value="../music/Beethoven-Symphony-No9-1st.mp3%../adimg/Beethoven.jpg%1440%810">Beethoven - 交響曲第9番 ニ短調 Op.125 「合唱」 第1楽章</option>  
          <option value="../music/Beethoven-Symphony-No9-2nd.mp3%../adimg/Beethoven.jpg%1440%810">Beethoven - 交響曲第9番 ニ短調 Op.125 「合唱」 第2楽章</option>  
          <option value="../music/Beethoven-Symphony-No9-3rd.mp3%../adimg/Beethoven.jpg%1440%810">Beethoven - 交響曲第9番 ニ短調 Op.125 「合唱」 第3楽章</option>  
          <option value="../music/Beethoven-Symphony-No9-4th.mp3%../adimg/Beethoven.jpg%1440%810">Beethoven - 交響曲第9番 ニ短調 Op.125 「合唱」 第4楽章</option>
          <option value="../music/Beethoven-ViolinSonata-No5-Spring-1st.mp3%../adimg/violin3.png%1024%682">Beethoven - ヴァイオリンソナタ 第5番 「春」 第1楽章</option>  
          <option value="../music/Brahms-Violin-Concerto-3rd.mp3%../adimg/violin3.png%1024%682">Brahms - ブラームス:ヴァイオリン協奏曲 第3楽章</option>  
          <option value="../music/Brahms-ViolinSonata-No1-1st.mp3%../adimg/violin3.png%1024%682">Brahms - ヴァイオリンソナタ第1番「雨の歌」</option>  
          <option value="../music/Chopin-PianoConcerto-No1-1st.mp3%../adimg/piano_04.jpg%1200%600">Chopin - ピアノ協奏曲 第1番 ホ短調 Op.11 第1楽章</option>
          <option value="../music/Chopin-PianoConcerto-No1-2nd.mp3%../adimg/piano_04.jpg%1200%600">Chopin - ピアノ協奏曲 第1番 ホ短調 Op.11 第2楽章</option>
          <option value="../music/Chopin-PianoConcerto-No1-3rd.mp3%../adimg/piano_04.jpg%1200%600">Chopin - ピアノ協奏曲 第1番 ホ短調 Op.11 第3楽章</option>
          <option value="../music/Dvorak-Symphony-No9-From-the-New-World.mp3%../adimg/ai_02.jpg%600%600">Dvorak - 交響曲第9番「新世界から」第一楽章 </option>
          <option value="../music/Dvorak-Symphony-No.9-2nd.mp3%../adimg/ai_08.jpg%600%600">Dvorak - 交響曲第9番「新世界から」第二楽章 </option>
          <option value="../music/Dvorak-Symphony-No9-3rd.mp3%../adimg/ai_06.jpg%600%600">Dvorak - 交響曲第9番「新世界から」第三楽章 </option>
          <option value="../music/Dvorak-Symphony-No9-4th.mp3%../adimg/ai_05.jpg%600%6S00">Dvorak - 交響曲第9番「新世界から」第四楽章</option>
          <option value="../music/Grieg-PianoConcerto-1st.mp3%../adimg/piano_04.jpg%1400%800">Grieg:ピアノ協奏曲 イ短調 作品16 第1楽章</option>
          <option value="../music/Mahler-Symphony-No1-2nd.mp3%../adimg/horn2.jpg%1440%1400">Mahler - 交響曲第1番「巨人」第二楽章</option>
          <option value="../music/Mahler-Symphony-No5-4th.mp3%../adimg/mahler.png%1600%898">Mahler - 交響曲第5番 嬰ハ短調 第四楽章 </option>
          <option value="../music/Mahler-Symphony-No10-5th.mp3%../adimg/mahler2.png%1000%1000">Mahler - 交響曲 第10番 嬰ヘ長調 第5楽章</option>
          <option value="../music/Mahler-Symphony-No10-5th.mp3%../adimg/mahler2.png%1000%1000">Mahler - 交響曲 第10番 嬰ヘ長調 第5楽章</option>
          <option value="../music/Mendelssohn-Violin-Concerto-1st.mp3%../adimg/violin_ai1.jpg%1000%1000">Mendelssohn:ヴァイオリン協奏曲 ホ短調 Op.64 第1楽章 </option>
          <option value="../music/Mendelssohn-Violin-Concerto-2nd.mp3%../adimg/violin_ai2.jpg%1000%1000">Mendelssohn:ヴァイオリン協奏曲 ホ短調 Op.64 第2楽章</option>
          <option value="../music/Mozart-Marriage-of-Figaro-Overture.mp3%../adimg/figaro1.jpg%1350%900">Mozart - 歌劇《フィガロの結婚》序曲 K.492</option>
          <option value="../music/Mozart-Symphony-No25-1st.mp3%../adimg/jupiter.jpg%1280%800">Mozart - 交響曲第25番 第一楽章</option>
          <option value="../music/Mozart-Magic-Flute-Overture.mp3%../adimg/mateki3.jpg%1340%812">Mozart - 歌劇 《魔笛》 序曲 K.620</option>
          <option value="../music/Mozart-Piano-Concerto-No20-1st.mp3%../adimg/Gulda.jpg%1200%1200">Mozart - ピアノ協奏曲 第20番 ニ短調 K.466</option>
          <option value="../music/Mozart-PianoConcerto-No21-2nd.mp3%../adimg/Gulda.jpg%1200%1200">Mozart - ピアノ協奏曲 第21番 ハ長調 K.467</option>
          <option value="../music/Mozart-PianoConcerto-No23-2nd.mp3%../adimg/Gulda.jpg%1200%1200">Mozart - ピアノ協奏曲 第23番 イ長調 K.488</option>
          <option value="../music/Mozart-SymNo41-1.mp3%../adimg/jupiter.jpg%1200%800">Mozart - 交響曲第41番「Jupiter」第一楽章</option>
          <option value="../music/Mozart-Symphony-No41-2nd.mp3%../adimg/jupiter.jpg%1200%800">Mozart - 交響曲第41番「Jupiter」第二楽章</option>
          <option value="../music/Mozart-Symphony-No41-3rd.mp3%../adimg/jupiter.jpg%1200%800">Mozart - 交響曲第41番「Jupiter」第三楽章</option>
          <option value="../music/Mozart-Symphony-No41-4th.mp3%../adimg/jupiter.jpg%1200%800">Mozart - 交響曲第41番「Jupiter」第四楽章</option>
          <option value="../music/Rachmaninov-PianoConcerto-No2-1st.mp3%../adimg/piano_08.jpg%1280%820"> Rachmaninov - ピアノ協奏曲 第2番 第一楽章</option>
          <option value="../music/Rachmaninov-PfConNo2-2.mp3%../adimg/piano_08.jpg%1280%820"> Rachmaninov - ピアノ協奏曲 第2番  第二楽章</option>
          <option value="../music/Rachmaninov-Piano-Concerto-No2-3rd.mp3%../adimg/piano_08.jpg%1280%820">Rachmaninov - ピアノ協奏曲 第2番  第三楽章</option>
           <option value="../music/Smetana-The-Moldau.mp3%../adimg/praha.jpg%1560%1040">Smetanar - 交響詩 《モルダウ》(わが祖国より)</option>
          <option value="../music/Tchaikovsky-PianoConcerto-No1-1st.mp3%../adimg/suntoryhall1.jpg%1600%700">Tchaikovsky - ピアノ協奏曲 第1番 第一楽章</option>
          <option value="../music/Tchaikovsky-PianoConcerto-No1-2nd.mp3%../adimg/suntoryhall1.jpg%1600%700">Tchaikovsky - ピアノ協奏曲 第1番 第二楽章</option>
          <option value="../music/Tchikovsky-PianoConcertoNo1-3.mp3%../adimg/suntoryhall1.jpg%1600%700">Tchaikovsky - ピアノ協奏曲 第1番 第三楽章</option>
          <option value="../music/Tchaikovsky-Symphony-No4-4th.mp3%../adimg/suntoryhall1.jpg%1600%700">Tchaikovsky - 交響曲 第4番 第4楽章</option>
      </optgroup>
      </select>
      </form>
      </div>    
      <canvas id="myCanvas"></canvas>
    </body>
    </html>
    
    

    css

    
    body {
     margin: 0;
     background-color:#000000;
     overflow: hidden;
     font-family: "Titillium Web", sans-serif;
    }
    #text {
      margin-top: -50px;
    }
    
    #btn_box {
      width: 100%;
    }
    #btn_box button {
      border: 1px solid aliceblue;
      border-radius: 2px;
      color: gold;
      margin: 0px auto;
      background: transparent;
    }
    #btnStart,
    #btnStop {
      padding: 5px;
    }
    #timer {
      width: 15%;
      font-size: 0.8rem;
      color: white;
      text-align: left;
      margin-right: 0.8rem;
      text-shadow: 0px 0px 10px black;
    }
    #music_title {
      color: gold;
    }
    @media (max-width: 480px) {
      #music_title {
        font-size: 0.8rem;
      }
    }
    
    

    KiricoCube2.js(全体)

    
    // ------------------------- Kirico cube v2 with audio  2023/07/12
    import * as THREE from "three";
    // import { OrbitControls } from "three/addons/controls/OrbitControls.js";
    import { FontLoader } from "./FontLoader.js";
    import { TextGeometry } from "./TextGeometry.js";
    import * as BufferGeometryUtils from "three/addons/utils/BufferGeometryUtils.js";
    
    // ----- Start butoon ------------------------------------
    btnStart.addEventListener("click", (value) => {
      btnStart.hidden = true;
      btnStop.hidden = false;
      Select_box.hidden = true;
      const music1 = document.form1.music1;
      const num = music1.selectedIndex;
      const str = music1.options[num].value;
      var str2 = str.split('%', 5);
      var music = str2[0];         // music mp3
      var imgf = str2[1];           // img file jpg
      var imgw = str2[2];         // img width
      var imgh = str2[3];          // img height
      var shape = str2[4];        // style sphere or cube
    
      if (imgf === "") { var imgf = "../adimg/record.jpg", imgw = 1200, imgh = 630 }; // defult img set
    
      var mtitle = music.replace(".mp3", "").replace("./music/", "").replace("./music2/", "").replace(".", "").replace("-", " ");
      console.log(mtitle)
      document.getElementById("timer").textContent = "loading ... ";
      document.getElementById("music_title").textContent = " " + mtitle + " ";
      var loader = new THREE.TextureLoader();
    
      // winodows size get
      const canvasElement = document.querySelector("#myCanvas");
      const width = window.innerWidth;
      const height = window.innerHeight;
      // -------------------------------------------  constant set 
      const fft_size = 512;  // fft size 
      var audioDuration = 0;
      let h2 = 0;
      var endflag = 0;
      var tmsh = 0; // textMesh defined 
      let radiuscamera = width<480 ? width*8 : width *4;
      var anglecamera = 0;              // camera angle 
      let crotsw = 1;  // camera rotation
      let m1defsw = 0;  // mesh1 defined
      var Myreq;  // animationframe id 
      let cyarg = 0.2;  // camera y move arg 
      let czarg = 1;  // camera z move arg 
    
      // ------------ audio --------------------------------------------------------
    
      const audioElement = new Audio(music);
      const context = new AudioContext();                       // audio context define  
      var ctimesave = 0;         // timer save
      audioElement.play();
      audioElement.addEventListener("loadedmetadata", function (e) {
        audioDuration = audioElement.duration;   // 再生総時間を取得する
      });
    
      // -------------------------------------
      // audio analize
      // -------------------------------------
      let nodeAnalyser = null;
      const freqByteDataArray = [];
      // -----  initalize
      for (let i = 0; i < fft_size / 2; i++) {
        const array = new Uint8Array(fft_size / 2);
        for (let j = 0; j < fft_size / 2; j++) {
          array[j] = 0;
        }
        freqByteDataArray.push(array);
      }
    
      initSound();
    
      function initSound() {
        const obj = analyseSound(audioElement);
        nodeAnalyser = obj.nodeAnalyser;
      }
      // -- analizer 
      function analyseSound(audioElement) {
        const nodeAnalyser = context.createAnalyser();
        nodeAnalyser.fftSize = fft_size;
        nodeAnalyser.smoothingTimeConstant = 0.9;
        nodeAnalyser.connect(context.destination);
        const nodeSource = context.createMediaElementSource(audioElement);
        nodeSource.connect(nodeAnalyser);
        return { nodeAnalyser };
      }
    
      // ----------------- 3d define ------------------------------------------------
    
      // レンダラーを作成
      const renderer = new THREE.WebGLRenderer({
        canvas: canvasElement, alpha: true
      });
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(width, height);
      //  renderer.setClearColor(0xb0c4de);
      // シーンを作成
      const scene = new THREE.Scene();
    
      // カメラを作成
      let cposx = 0;     // camera position initial 
      let cposy = 0;
      let cposz = radiuscamera;
    
      let anglecamera_x = 0 ;     // camera move 
      let anglecamera_y = 0 ;
      let anglecamera_z = 0 ;
    
      const camera = new THREE.PerspectiveCamera(45, width / height, 1, 13000);
      camera.aspect = width / height;
      camera.updateProjectionMatrix();
      camera.position.set(cposx, cposy, cposz);   // -- position initial 
    
      // ------------------  sphere define 
      if (typeof shape === "undefined") {                     //  shape not defined 
        document.body.style.backgroundImage = "url(" + imgf + ")";     // --- background image 
        document.body.style.backgroundRepeat = "no-repeat";
        document.body.style.backgroundPosition = "50% 50%";  // x y
        document.body.style.backgroundSize = 30 * imgw / width + "%";
      };
    
      var ssz = 0.2;
      var mposx = 0;    // sphere position 
      var mposy = 0;
      var mposz = 0;
      var geometry1 = new THREE.SphereGeometry(imgw * ssz, imgh * ssz, 100)
      var material1 = new THREE.MeshPhongMaterial({ map: loader.load(imgf), transparent: true, opacity: 1 });
      const mesh1 = new THREE.Mesh(geometry1, material1);
    
      if (shape === "sphere") {
        scene.add(mesh1);
        mesh1.position.set(mposx, mposy, mposz) // image position 
        m1defsw = 1;
      };
    
      // 1辺あたりに配置するオブジェクトの個数
      const cell_num = 50;
      // 結合用のジオメトリを格納する配列
      const boxes = [];
      for (let i = 0; i < cell_num; i++) {
        for (let j = 0; j < cell_num; j++) {
          for (let k = 0; k < cell_num; k++) {
            // 立方体個別の要素を作成
            const geometrySphere = new THREE.SphereGeometry(2, 2, 2);
            // 座標調整
            const geow = 50;  // 間隔
            const geometryTranslated = geometrySphere.translate(
              geow * (i - cell_num / 2),
              geow * (j - cell_num / 2),
              geow * (k - cell_num / 2)
            );
            // ジオメトリを保存
            boxes.push(geometryTranslated);
          }
        }
      }
      // box ジオメトリを生成
      const geometry = BufferGeometryUtils.mergeGeometries(boxes);
      // マテリアルを作成
      const material = new THREE.MeshStandardMaterial({ color: 0xffffff, wireframe: true });
      // メッシュを作成
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);
    
      // ------------------------------------------------- 
      //    text define  
      //    textMesh : page title  
      // ------------------------------------------------- 
      const fsize = 30;
      var text = mtitle;
      if (tmsh == 1) { scene.remove(textMesh) }
      const loadert = new FontLoader()
      loadert.load('./fonts/optimer_regular.typeface.json', function (font) {
        const textGeometry = new TextGeometry(text, {
          font: font,
          size: fsize,
          height: 1,
        });
        const textMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff });
        var textMesh = new THREE.Mesh(textGeometry, textMaterial);
        scene.add(textMesh);
        textGeometry.center();         // text on center position set
        textMesh.position.set(0, 200, 0);
        textMesh.rotation.set(- Math.PI / 5, 0, 0);
      });
    
      // --------------------- 環境光 を作成 -------------------------------
      const ambientLight = new THREE.AmbientLight(0x444444);
      scene.add(ambientLight);
    
      // ------------------ spotlight ---------------------------------------
      // new THREE.SpotLight(色, 光の強さ, 距離, 照射角, ボケ具合, 減衰率)
      var cpz = 500;
      const spotLight1 = new THREE.SpotLight(0xffffff, 1.0, 2000, Math.PI / 8, 1, 0);
      spotLight1.position.set(0, 0, 1500);
      scene.add(spotLight1);
      const spotLight2 = new THREE.SpotLight(0xffffff, 1.0, 2000, Math.PI / 2, 1, 0);
      spotLight2.position.set(0, 0, 2000);
      scene.add(spotLight2);
    
      // const spotLightHelper1 = new THREE.SpotLightHelper( spotLight1);
      // scene.add( spotLightHelper1 );
      // const spotLightHelper2 = new THREE.SpotLightHelper( spotLight2);
      // scene.add( spotLightHelper2 );
    
      // カメラコントローラー
      // const controls = new OrbitControls(camera, canvasElement);
      // ----------------------------   define ground grid 
      const gridColor = new THREE.Color(0x84a2d4);
      const grid_size = 8000;
      const grid1 = new THREE.GridHelper(grid_size, 100, gridColor, gridColor);
      grid1.position.y = -height * 2;
      scene.add(grid1);
    
      // ------- tick ---------------
    
      tick();
    
      // 毎フレーム時に実行されるループイベントです  
      function tick() {
    
        const ctime = parseInt(context.currentTime);
        const dtime = parseInt(audioDuration);  //-- audio duration 
        if (ctime > ctimesave || typeof ctimesave === "undefined") {
    
          if (ctime <= dtime && typeof audioDuration !== "undefined" && endflag !== 1) {
            var str2 = ctime + " / " + dtime;
            document.getElementById("timer").textContent = str2;
            if (ctime >= dtime) { endflag = 1, endproc() };  // ------- end proc
          };
          if (dtime > 600 && ctime % 300 === 0) { crotsw = crotsw * -1 };  // change camera rotation 
          ctimesave = ctime;
        };
    
        const freqByteData = new Uint8Array(fft_size / 2);
        nodeAnalyser.getByteFrequencyData(freqByteData);
        freqByteDataArray.push(freqByteData);
    
        var value0 = freqByteData[0] / 256   // rotation angle , color 
        var value1 = freqByteData[1] / 256;   // 
        var value2 = freqByteData[2] / 256;   // 
    
        // カラー生成 hue  , saturation , lightness  between 0 - 1.0 hue 0 red
        spotLight1.color.setHSL(value0, 1, 0.6);
        h2 = h2 < 1 ? h2 += 0.001 : 0;
        spotLight2.color.setHSL(h2, 1, 0.6)
    
        // camera move 
        if (radiuscamera >= 1000) { radiuscamera -= 1; let cyarg = 0.5 };  // mesh1 に接近
    
        anglecamera_x += crotsw * value0 / 10;
        anglecamera_y += crotsw * value1 / 10;
        anglecamera_z += crotsw * value2 / 10;
    
        camera.position.x = radiuscamera * Math.cos(Math.PI / 180 * anglecamera_x);
        camera.position.y = radiuscamera * Math.cos(Math.PI / 180 * anglecamera_y) * cyarg;
        camera.position.z = radiuscamera * Math.sin(Math.PI / 180 * anglecamera_z) * czarg;
        camera.lookAt(new THREE.Vector3(0, 0, 0));  // 中央に向ける
    
        spotLight1.position.x = radiuscamera * Math.cos(Math.PI / 180 * anglecamera_x);
        spotLight1.position.y = radiuscamera * Math.cos(Math.PI / 180 * anglecamera_y) * cyarg;
        spotLight1.position.z = radiuscamera * Math.sin(Math.PI / 180 * anglecamera_z) * czarg;
        spotLight1.lookAt(new THREE.Vector3(0, 0, 0));  // 中央に向ける
    
        anglecamera += crotsw * value0 / 10;
    
        //   spotLight1.target.position.setFromMatrixPosition(camera.matrixWorld);
    
        if (m1defsw === 1) {
          mesh1.rotation.y += 0.002;
        };
    
        // レンダリング
        renderer.render(scene, camera);
        var Myreq = requestAnimationFrame(tick);
    
      }; // tick end
    
      // ----------- stop button 
      btnStop.addEventListener("click", (value) => {
        audioElement.pause();
        btnStart.hidden = false;
        btnStop.hidden = true;
        Select_box.hidden = false;
        cancelAnimationFrame(Myreq);
        location.reload()
      });
      // ----------------- endproc 
      function endproc() {
        document.getElementById("timer").textContent = " end...push Stop ..";
        document.getElementById("music_title").textContent = " ";
        camera.position.set(cposx, cposy, cposz);   // -- position initial 
        scene.remove(mesh, grid1);
        cancelAnimationFrame(Myreq);
        Select_box.hidden = false;
        //   location.reload()
      };
    
      // resize
      window.addEventListener('resize', onResize);
      function onResize() {
        const width = window.innerWidth;
        const height = window.innerHeight;
        camera.aspect = width / height;
        camera.updateProjectionMatrix();
        renderer.setSize(width, height);
      };
    });  // init end 
    
    

    以下、KiricoCube2.jsを機能別に説明

    KiricoCube2.js : モジュールimport , button処理

    
    // ------------------------- Kirico cube v2 with audio  2023/07/12
    import * as THREE from "three";
    // import { OrbitControls } from "three/addons/controls/OrbitControls.js";
    import { FontLoader } from "./FontLoader.js";
    import { TextGeometry } from "./TextGeometry.js";
    import * as BufferGeometryUtils from "three/addons/utils/BufferGeometryUtils.js";
    
    // ----- Start butoon ------------------------------------
    btnStart.addEventListener("click", (value) => {
      btnStart.hidden = true;
      btnStop.hidden = false;
      Select_box.hidden = true;
      const music1 = document.form1.music1;
      const num = music1.selectedIndex;
      const str = music1.options[num].value;
      var str2 = str.split('%', 5);
      var music = str2[0];         // music mp3
      var imgf = str2[1];           // img file jpg
      var imgw = str2[2];         // img width
      var imgh = str2[3];          // img height
      var shape = str2[4];        // style sphere or cube
    
      if (imgf ==="") {var imgf="../adimg/record.jpg" , imgw = 1200 , imgh = 630 }; // defult img set
    
      var mtitle = music.replace(".mp3", "").replace("./music/", "").replace("./music2/", "").replace(".", "").replace("-", " ");
      console.log(mtitle)
      document.getElementById("timer").textContent = "loading ... ";
      document.getElementById("music_title").textContent = " " + mtitle + " ";
      var loader = new THREE.TextureLoader();
    
    // canvas size get
      const canvasElement = document.querySelector("#myCanvas");
      const width = window.innerWidth;
      const height = window.innerHeight;
    
    

    KiricoCube2.js : audio api

    
     // ------------ audio --------------------------------------------------------
      const audioElement = new Audio(music);
      const context = new AudioContext();                       // audio context define  
      var ctimesave = 0;         // timer save
      audioElement.play();
      audioElement.addEventListener("loadedmetadata", function (e) {
        audioDuration = audioElement.duration;   // 再生総時間を取得する
      });
      // -------------------------------------
      // audio analize
      // -------------------------------------
      let nodeAnalyser = null;
      const freqByteDataArray = [];
      // -----  initalize
      for (let i = 0; i < fft_size / 2; i++) {
        const array = new Uint8Array(fft_size / 2);
        for (let j = 0; j < fft_size / 2; j++) {
          array[j] = 0;
        }
        freqByteDataArray.push(array);
      }
      initSound();
      function initSound() {
        const obj = analyseSound(audioElement);
        nodeAnalyser = obj.nodeAnalyser;
      }
      // -- analizer 
      function analyseSound(audioElement) {
        const nodeAnalyser = context.createAnalyser();
        nodeAnalyser.fftSize = fft_size;
        nodeAnalyser.smoothingTimeConstant = 0.9;
        nodeAnalyser.connect(context.destination);
        const nodeSource = context.createMediaElementSource(audioElement);
        nodeSource.connect(nodeAnalyser);
        return { nodeAnalyser };
      }
    
    

    KiricoCube2.js : 3D 定義

    
     // ----------------- 3d define ------------------------------------------------
      
      // レンダラーを作成
      const renderer = new THREE.WebGLRenderer({
        canvas: canvasElement, alpha: true
      });
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(width, height);
      //  renderer.setClearColor(0xb0c4de);
      // シーンを作成
      const scene = new THREE.Scene();
    
      // カメラを作成
      let cposx = 0;     // camera position initial 
      let cposy = 0;
      let cposz = radiuscamera;
    
      let anglecamera_x = 0 ;     // camera move 
      let anglecamera_y = 0 ;
      let anglecamera_z = 0 ;
    
      const camera = new THREE.PerspectiveCamera(45, width / height, 1, 13000);
      camera.aspect = width / height;
      camera.updateProjectionMatrix();
      camera.position.set(cposx, cposy, cposz);   // -- position initial 
      
      // ------------------  sphere define 
      if (typeof shape === "undefined") {                     //  shape not defined 
        document.body.style.backgroundImage = "url(" + imgf + ")";     // --- background image 
        document.body.style.backgroundRepeat = "no-repeat";
        document.body.style.backgroundPosition = "50% 50%";  // x y
        document.body.style.backgroundSize = 30 * imgw / width + "%";
      };
    
      var ssz = 0.2;
      var mposx = 0;    // sphere position 
      var mposy = 0;
      var mposz = 0;
      var geometry1 = new THREE.SphereGeometry(imgw * ssz, imgh * ssz, 100)
      var material1 = new THREE.MeshPhongMaterial({ map: loader.load(imgf), transparent: true, opacity: 1 });
      const mesh1 = new THREE.Mesh(geometry1, material1);
    
      if (shape === "sphere") {
        scene.add(mesh1);
        mesh1.position.set(mposx, mposy, mposz) // image position 
        m1defsw = 1;
      };
    
      // 1辺あたりに配置するオブジェクトの個数
      const cell_num = 50;
      // 結合用のジオメトリを格納する配列
      const boxes = [];
      for (let i = 0; i < cell_num; i++) {
        for (let j = 0; j < cell_num; j++) {
          for (let k = 0; k < cell_num; k++) {
            // 立方体個別の要素を作成
            const geometrySphere = new THREE.SphereGeometry(2, 2, 2);
            // 座標調整
            const geow = 50 ;  // 間隔
            const geometryTranslated = geometrySphere.translate(
              geow * (i - cell_num / 2),
              geow * (j - cell_num / 2),
              geow * (k - cell_num / 2)
            );
            // ジオメトリを保存
            boxes.push(geometryTranslated);
          }
        }
      }
      // box ジオメトリを生成
      const geometry = BufferGeometryUtils.mergeGeometries(boxes);
      // マテリアルを作成
      const material = new THREE.MeshStandardMaterial({ color: 0xffffff, wireframe: true });
      // メッシュを作成
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);
    
      // ------------------------------------------------- 
      //    text define  
      //    textMesh : page title  
      // ------------------------------------------------- 
      const fsize = 20;
      var text = mtitle;
      if (tmsh == 1) { scene.remove(textMesh) }
      const loadert = new FontLoader()
      loadert.load('./fonts/optimer_regular.typeface.json', function (font) {
        const textGeometry = new TextGeometry(text, {
          font: font,
          size: fsize,
          height: 1,
        });
        const textMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff });
        var textMesh = new THREE.Mesh(textGeometry, textMaterial);
        scene.add(textMesh);
        textGeometry.center();         // text on center position set
        textMesh.position.set(0, 200, 0);
        textMesh.rotation.set(- Math.PI / 5, 0, 0);
      });
    
      // ------------------ spotlight ---------------------------------------
      // new THREE.SpotLight(色, 光の強さ, 距離, 照射角, ボケ具合, 減衰率)
      var cpz = 500;
      const spotLight1 = new THREE.SpotLight(0xffffff, 1.0 , 2000 , Math.PI/8, 1, 0);
      spotLight1.position.set(0, 0, 1500);
      scene.add(spotLight1);
      const spotLight2 = new THREE.SpotLight(0xffffff, 1.0 , 2000 , Math.PI/2, 1, 0);
      spotLight2.position.set(0, 0, 2000);
      scene.add(spotLight2);
       
      // const spotLightHelper1 = new THREE.SpotLightHelper( spotLight1);
      // scene.add( spotLightHelper1 );
      // const spotLightHelper2 = new THREE.SpotLightHelper( spotLight2);
      // scene.add( spotLightHelper2 );
    
      // カメラコントローラー
      // const controls = new OrbitControls(camera, canvasElement);
      // ----------------------------   define ground grid 
      const gridColor = new THREE.Color(0x84a2d4);
      const grid_size = 8000;
      const grid1 = new THREE.GridHelper(grid_size, 100, gridColor, gridColor);
      grid1.position.y = -height * 2;
      scene.add(grid1);
    
    

    KiricoCube2.js : animation frame

    
     // ------- tick ---------------
    
      tick();
    
      // 毎フレーム時に実行されるループイベントです  
      function tick() {
    
        const ctime = parseInt(context.currentTime);
        const dtime = parseInt(audioDuration);  //-- audio duration 
        if (ctime > ctimesave || typeof ctimesave === "undefined") {
    
          if (ctime <= dtime && typeof audioDuration !== "undefined" && endflag !== 1) {
            var str2 = ctime + " / " + dtime;
            document.getElementById("timer").textContent = str2;
            if (ctime >= dtime) { endflag = 1, endproc() };  // ------- end proc
          };
          if (dtime > 600 && ctime % 300 === 0) { crotsw = crotsw * -1 };  // change camera rotation 
          ctimesave = ctime;
        };
    
        const freqByteData = new Uint8Array(fft_size / 2);
        nodeAnalyser.getByteFrequencyData(freqByteData);
        freqByteDataArray.push(freqByteData);
        
        var value0 = freqByteData[0] / 256   // rotation angle  , color
        var value1 = freqByteData[1] / 256;   //   
        var value2 = freqByteData[2] / 256;   // 
    
        // カラー生成 hue  , saturation , lightness  between 0 - 1.0 hue 0 red
        spotLight1.color.setHSL(value0, 1, 0.6);
        h2 = h2 < 1 ? h2 += 0.001 : 0;
        spotLight2.color.setHSL(h2, 1, 0.6)
    
        // camera move 
        if (radiuscamera >= 1000) { radiuscamera -= 1; let cyarg = 0.5 };  // mesh1 に接近
    
        anglecamera_x += crotsw * value0 / 10;
        anglecamera_y += crotsw * value1 / 10;
        anglecamera_z += crotsw * value2 / 10;
    
        camera.position.x = radiuscamera * Math.cos(Math.PI / 180 * anglecamera_x);
        camera.position.y = radiuscamera * Math.cos(Math.PI / 180 * anglecamera_y) * cyarg;
        camera.position.z = radiuscamera * Math.sin(Math.PI / 180 * anglecamera_z) * czarg;
        camera.lookAt(new THREE.Vector3(0, 0, 0));  // 中央に向ける
    
        spotLight1.position.x = radiuscamera * Math.cos(Math.PI / 180 * anglecamera_x);
        spotLight1.position.y = radiuscamera * Math.cos(Math.PI / 180 * anglecamera_y) * cyarg;
        spotLight1.position.z = radiuscamera * Math.sin(Math.PI / 180 * anglecamera_z) * czarg;
        spotLight1.lookAt(new THREE.Vector3(0, 0, 0));  // 中央に向ける
    
        if (m1defsw === 1) {
          mesh1.rotation.y += 0.002;
        };
    
       // レンダリング
        renderer.render(scene, camera);
        var Myreq = requestAnimationFrame(tick);
    
      }; // tick end
    
    

    KiricoCube2.js : stop ボタン、end、reSize 処理

    
    // ----------- stop button 
      btnStop.addEventListener("click", (value) => {
        audioElement.pause();
        btnStart.hidden = false;
        btnStop.hidden = true;
        Select_box.hidden = false;
        cancelAnimationFrame(Myreq);
        location.reload()
      });
      // ----------------- endproc 
      function endproc() {
        document.getElementById("timer").textContent = " end...push Stop ..";
        document.getElementById("music_title").textContent = " ";
        camera.position.set(cposx, cposy, cposz);   // -- position initial 
        scene.remove(mesh,grid1);
        cancelAnimationFrame(Myreq);
        Select_box.hidden = false;
     //   location.reload()
      };
    
      // resize
      window.addEventListener('resize', onResize);
      function onResize() {
        const width = window.innerWidth;
        const height = window.innerHeight;
        camera.aspect = width / height;
        camera.updateProjectionMatrix();
        renderer.setSize(width, height);
      };
    });  // init end 
    
    

    AIの活用

    今年になってマスコミなどでもChatGPTなどのAIに関する記事が頻繁に載るようになった。 自分でもウェブでの情報発信に活用している。

    MicroSoft社のBingもチャット(会話)AIだがimage createrもこのAIのアプリとして使える。3D作品のパーツとして音楽にに合った画像を使う際に、AIを利用して作成しているものもある。

    この画像はimage createrに「ベートーベンの交響曲「運命」のイメージにあう画像を作って」とプロンプトして作られたうちの一枚。同じくベートーベンの「エリーゼのために」の画像として使った。画像の左下に" lb"のロゴを表示してあれば著作権は問わないという。

    コーデングでも活用できる。「three.jsでspotlightのカラーを動的に変化させる方法」というプロンプトに対する回答:
    // スポットライト光源を作成
    const light = new THREE.SpotLight(0xFFFFFF, 4, 30, Math.PI / 4, 10, 0.5);
    scene.add(light);
    // スポットライトの色を変更
    light.color.setHex(0xFF0000);

    もうすでに、プログラム言語を知らなくても、指示するだけでAIがプログラムを作ってブラウザで実行し結果を表示してくれるという。