New Features and Cosmetics

* Adds option to toggle fullscreen
* Adds option to hide controls and hide music player(just visualization only)
* Font Changes
* Adds Stylized tooltips
This commit is contained in:
2025-06-30 02:37:28 +05:30
parent c708bb42da
commit ae44e79a15
4 changed files with 503 additions and 307 deletions

Binary file not shown.

59
hg.css
View File

@@ -2,6 +2,10 @@
font-family: "StreamSter";
src: url(./fonts/Streamster.ttf);
}
@font-face {
font-family: "VCR";
src: url(./fonts/VCR_OSD_MONO_1.001.ttf);
}
#app,
body,
html {
@@ -15,7 +19,7 @@ body {
padding: 0;
margin: 0;
background: #fafafa;
font-family: "Helvetica Neue", arial, sans-serif;
font-family: "VCR", arial, sans-serif;
font-weight: 400;
color: #444;
-webkit-font-smoothing: antialiased;
@@ -131,7 +135,8 @@ h3#track-name {
font-weight: 500;
letter-spacing: 2px;
color: #e91e63;
font-family: "StreamSter", sans-serif;
/* font-family: "StreamSter", sans-serif; */
font-family: "VCR", sans-serif;
margin-bottom: 0;
background: rgb(0 0 0 / 71%);
padding: 10px;
@@ -149,7 +154,7 @@ hr {
width: 170px;
margin: 0 auto;
color: #dce3e7;
font-family: "Droid Serif", serif;
font-family: "VCR", serif;
font-size: 13px;
font-style: italic;
line-height: 18px;
@@ -247,19 +252,23 @@ dialog::backdrop {
.controls {
font-style: italic;
font-size: larger;
color: #ff0095;
}
.footer {
position: absolute;
bottom: 0px;
width: 350px;
width: 342px;
display: flex;
color: #ffffff;
z-index: 999;
justify-content: center;
height: 17px;
}
.footer .footer-items {
font-size: 13px;
font-family: "VCR", serif;
text-decoration: none;
cursor: pointer;
padding-left: 10px;
@@ -267,15 +276,53 @@ dialog::backdrop {
justify-content: center;
}
.footer-items#history {
margin-top: 3px;
}
canvas {
position: absolute;
top: 0;
}
.refresh {
.buttons {
z-index: 999;
cursor: pointer;
position: relative;
float: right;
user-select: none;
}
.refresh {
float: right;
}
.fullscreen {
float: left;
float: left;
margin-left: 5px;
margin-top: 3px;
color: #565656;
}
.fullscreen svg {
height: 10px;
width: 10px;
color: #ffffffff;
}
.fullscreen:hover * {
color: #ffffff;
}
.hidden {
display: none;
}
.OVR {
position: absolute;
bottom: 0;
z-index: 999;
color: #ffff;
right: 0;
margin-right: 5px;
}

View File

@@ -1,62 +1,128 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Retrowave Player</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.2.3/howler.min.js"></script>
<script src="https://unpkg.com/hydra-synth"></script>
<link rel="stylesheet" href="hg.css">
<link rel="icon" href="/favicon.ico">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
</head>
<link rel="stylesheet" href="hg.css" />
<link rel="icon" href="/favicon.ico" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
</head>
<body>
<body>
<div class="modal" id="intro-modal">
<div class="modal-bg modal-exit"></div>
<div class="modal-container">
<h3 class="text-center">Welcome to Retrowave Player</h3>
<p class="mt-5">Here are the controls:</p>
<h4 class="mt-5">Play/Pause <span class="controls">SPACE or Click or Touch</span></h4>
<h4 class="mt-5">Volume Up <span class="controls">w or Swipe Up</span></h4>
<h4 class="mt-5">Volume Down <span class="controls">s or Swipe Down</span></h4>
<h4 class="mt-5">Next Track<span class="controls"> n or Press the Refresh Button</span></h4>
<p class="mt-5">(You can download the music history of your current browser by clicking the history link on
the player)</p>
<p class="mt-5">All the music is fetched from retrowave.ru</p>
<button class="modal-close modal-exit" id="initButton">X</button>
</div>
<div class="modal-bg modal-exit"></div>
<div class="modal-container">
<h3 class="text-center">Welcome to Retrowave Player</h3>
<p class="mt-5">Here are the controls:</p>
<h4 class="mt-5">
Play/Pause <span class="controls">SPACE or Click or Touch</span>
</h4>
<h4 class="mt-5">
Volume Up <span class="controls">w or Swipe Up</span>
</h4>
<h4 class="mt-5">
Volume Down <span class="controls">s or Swipe Down</span>
</h4>
<h4 class="mt-5">
Next Track<span class="controls"> n or Press the Refresh Button</span>
</h4>
<h4 class="mt-5">
Toggle Controls<span class="controls"> h</span>
</h4>
<p class="mt-5">
(You can download the music history of your current browser by
clicking the history link on the player)
</p>
<p class="mt-5">All the music is fetched from retrowave.ru</p>
<button class="modal-close modal-exit" id="initButton">X</button>
</div>
</div>
<div id="app">
<div class="music-player">
<div class="no-pause refresh">🔃</div>
<div class="title-content">
<div class="intro">Now Playing</div>
<hr>
<h3 id="track-name">Retrowave Player</h3>
</div>
<div class="gradient-overlay"></div>
<div class="color-overlay"></div>
<div class="footer">
<div id="history" class="no-pause footer-items">history</div>
<div id="source"><a class="no-pause footer-items" href="https://git.indrajith.dev/retrowave-player/"
target="_blank">source code</a></div>
<div id="retrowaveru" class="no-pause"><a class="no-pause footer-items" href="http://retrowave.ru/"
target="_blank">retrowave.ru</a></div>
<div id="guestbook" class="no-pause"><a class="no-pause footer-items" href="https://indrajith.atabook.org/"
target="_blank">guestbook</a></div>
</div>
<!-- <div id="upload-info" class="no-pause" title="Upload a playlist (downloaded from history)">Upload</div> -->
<div class="music-player">
<div title="FULLSCREEN" class="no-pause buttons fullscreen toggleable">
<svg
class="no-pause"
width="800px"
height="800px"
fill="#000000"
version="1.1"
viewBox="0 0 384.97 384.97"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
>
<g style="fill: #f9f9f9">
<g id="Fullscreen" style="fill: #f9f9f9">
<path
d="m384.97 12.03c0-6.713-5.317-12.03-12.03-12.03h-108.09c-6.833 0-11.922 5.39-11.934 12.223 0 6.821 5.101 11.838 11.934 11.838h96.062l-0.193 96.519c0 6.833 5.197 12.03 12.03 12.03 6.833-0.012 12.03-5.197 12.03-12.03l0.193-108.37c0-0.036-0.012-0.06-0.012-0.084 1e-3 -0.037 0.013-0.061 0.013-0.097z"
style="fill: #f9f9f9"
/>
<path
d="M120.496,0H12.403c-0.036,0-0.06,0.012-0.096,0.012C12.283,0.012,12.247,0,12.223,0C5.51,0,0.192,5.317,0.192,12.03 L0,120.399c0,6.833,5.39,11.934,12.223,11.934c6.821,0,11.838-5.101,11.838-11.934l0.192-96.339h96.242 c6.833,0,12.03-5.197,12.03-12.03C132.514,5.197,127.317,0,120.496,0z"
style="fill: #f9f9f9"
/>
<path
d="m120.12 360.91h-96.062v-96.242c0-6.833-5.197-12.03-12.03-12.03s-12.031 5.196-12.031 12.03v108.09c0 0.036 0.012 0.06 0.012 0.084 0 0.036-0.012 0.06-0.012 0.096 0 6.713 5.317 12.03 12.03 12.03h108.09c6.833 0 11.922-5.39 11.934-12.223 1e-3 -6.82-5.1-11.837-11.933-11.837z"
style="fill: #f9f9f9"
/>
<path
d="m372.75 252.91c-6.833 0-11.85 5.101-11.838 11.934v96.062h-96.242c-6.833 0-12.03 5.197-12.03 12.03s5.197 12.03 12.03 12.03h108.09c0.036 0 0.06-0.012 0.084-0.012 0.036-0.012 0.06 0.012 0.096 0.012 6.713 0 12.03-5.317 12.03-12.03v-108.09c1e-3 -6.833-5.389-11.934-12.222-11.934z"
style="fill: #f9f9f9"
/>
</g>
</g>
</svg>
</div>
<div class="no-pause buttons refresh toggleable" title="NEXT TRACK">🔃</div>
<div class="title-content">
<div class="intro">Now Playing</div>
<hr />
<h3 id="track-name">Retrowave Player</h3>
</div>
<div class="gradient-overlay"></div>
<div class="color-overlay"></div>
<div class="footer toggleable">
<div title="DOWNLOAD YOUR PLAYLIST HISTORY" id="history" class="no-pause footer-items">history</div>
<div id="source">
<a
title="SOURCE CODE"
class="no-pause footer-items"
href="https://git.indrajith.dev/retrowave-player/"
target="_blank"
>source code</a
>
</div>
<div id="retrowaveru" class="no-pause">
<a
title="RETROWAVE.RU"
class="no-pause footer-items"
href="http://retrowave.ru/"
target="_blank"
>retrowave.ru</a
>
</div>
<div id="guestbook" class="no-pause">
<a
title="SIGN MY GUESTBOOK"
class="no-pause footer-items"
href="https://indrajith.atabook.org/"
target="_blank"
>guestbook</a
>
</div>
</div>
<!-- <div id="upload-info" class="no-pause" title="Upload a playlist (downloaded from history)">Upload</div> -->
</div>
</div>
<div id="codef-canvas"></div>
<div class="OVR hidden"></div>
<input id="file-upload" type="file" accept="application/json" />
<!-- <script src="libs/codef_core.js"></script>
<script src="libs/codef_starfield.js"></script>
<script src="libs/codef_3d.js"></script> -->
<script src="player.js"></script>
</body>
</body>
</html>

595
player.js
View File

@@ -1,293 +1,376 @@
(function () {
let isPlaying = false;
let currentTracks = [];
let cursor = 0;
let howlerInstance;
const retroWaveRu = "https://retrowave.ru";
let titleEl = document.getElementById("track-name");
let coverArtEl = document.getElementsByClassName("music-player")[0];
let refreshBtn = document.querySelector(".refresh");
const modalEl = document.getElementById("intro-modal");
// const uploadInfoEl = document.getElementById("upload-info");
const fileUploadEl = document.getElementById("file-upload");
let volume = 1;
let effectCanvas;
let starField;
let line3D;
const synthwaveColor = 0xff2975;
let isPlaying = false;
let currentTracks = [];
let cursor = 0;
let howlerInstance;
const retroWaveRu = "https://retrowave.ru";
let titleEl = document.getElementById("track-name");
let coverArtEl = document.getElementsByClassName("music-player")[0];
let refreshBtn = document.querySelector(".refresh");
let ovr = document.querySelector(".OVR");
let fullScreenBtn = document.querySelector(".fullscreen");
const modalEl = document.getElementById("intro-modal");
// const uploadInfoEl = document.getElementById("upload-info");
const fileUploadEl = document.getElementById("file-upload");
let volume = 1;
let effectCanvas;
let starField;
let line3D;
const synthwaveColor = 0xff2975;
openDialog();
getMusic();
listenUploadFileChange();
openDialog();
getMusic();
listenUploadFileChange();
coverArtEl.addEventListener("click", (event) => {
const isNoPause = event.target.classList.contains("no-pause");
if (howlerInstance && !isNoPause) {
togglePlay();
function initDynamicTooltips() {
document.querySelectorAll("[title]").forEach((element) => {
const title = element.getAttribute("title");
element.removeAttribute("title");
element.setAttribute("data-title", title);
element.addEventListener("mouseenter", function (e) {
const tooltip = document.createElement("div");
tooltip.textContent = this.getAttribute("data-title");
tooltip.style.cssText = `
font-family: "VCR", sans-serif;
position: fixed;
background:rgb(255, 255, 255);
color: #000000;
border: 1px solidrgb(0, 0, 0);
padding: 4px 8px;
font-size: 12px;
border-radius: 3px;
z-index: 10000;
pointer-events: none;
white-space: nowrap;
`;
document.body.appendChild(tooltip);
this.tooltipEl = tooltip;
const rect = this.getBoundingClientRect();
tooltip.style.left =
rect.left + rect.width / 2 - tooltip.offsetWidth / 2 + "px";
tooltip.style.top = rect.top - tooltip.offsetHeight - 8 + "px";
});
element.addEventListener("mouseleave", function () {
if (this.tooltipEl) {
document.body.removeChild(this.tooltipEl);
this.tooltipEl = null;
}
});
});
}
document.addEventListener("DOMContentLoaded", initDynamicTooltips);
coverArtEl.addEventListener("click", (event) => {
const isNoPause = event.target.classList.contains("no-pause");
if (howlerInstance && !isNoPause) {
togglePlay();
}
});
// uploadInfoEl.addEventListener("click", () => {
// const confirmText = `Do you really want to change your playlist?\nThis will replace all your retrowave music history.\nIf you are sure about this, make sure to upload a valid json file probably downloaded using history link.`;
// if (confirm(confirmText)) {
// fileUploadEl.click();
// }
// });
function listenUploadFileChange() {
fileUploadEl.onchange = function () {
const selectedFile = fileUploadEl.files[0];
const reader = new FileReader();
reader.readAsText(selectedFile, "UTF-8");
reader.onload = function (event) {
try {
const uploadedPlaylist = JSON.parse(event.target.result);
localStorage.setItem("retrowave-history", event.target.result);
} catch (error) {
alert("malformed/invalid json file");
}
};
};
}
document.getElementById("initButton")?.addEventListener("click", () => {
var hydra = new Hydra({ detectAudio: false });
modalEl.classList.remove("open");
playMusic();
initHydra();
initControls();
});
document.getElementById("history").addEventListener("click", () => {
downloadHistory();
});
document.addEventListener("keyup", (event) => {
const { key } = event;
switch (key) {
case " ":
togglePlay();
break;
case "a":
break;
case "d":
break;
case "w":
volumeUp();
break;
case "s":
volumeDown();
break;
case "n":
playNextTrack();
break;
case "f":
toggleFullScreen();
break;
case "h":
toggleControls();
break;
case 'x':
toggleEverything();
}
});
let touchstartX = 0;
let touchendX = 0;
let touchstartY = 0;
let touchendY = 0;
const musixPlayerEl = document.getElementsByClassName("music-player")[0];
if (musixPlayerEl) {
musixPlayerEl.addEventListener("touchstart", (e) => {
touchstartX = e.changedTouches[0].screenX;
touchstartY = e.changedTouches[0].screenY;
});
// uploadInfoEl.addEventListener("click", () => {
// const confirmText = `Do you really want to change your playlist?\nThis will replace all your retrowave music history.\nIf you are sure about this, make sure to upload a valid json file probably downloaded using history link.`;
// if (confirm(confirmText)) {
// fileUploadEl.click();
// }
// });
function listenUploadFileChange() {
fileUploadEl.onchange = function () {
const selectedFile = fileUploadEl.files[0];
const reader = new FileReader();
reader.readAsText(selectedFile, "UTF-8");
reader.onload = function (event) {
try {
const uploadedPlaylist = JSON.parse(event.target.result);
localStorage.setItem("retrowave-history", event.target.result);
} catch (error) {
alert("malformed/invalid json file");
}
};
};
}
document.getElementById("initButton")?.addEventListener("click", () => {
var hydra = new Hydra({ detectAudio: false })
modalEl.classList.remove("open");
playMusic();
initHydra();
initControls();
musixPlayerEl.addEventListener("touchend", (e) => {
touchendX = e.changedTouches[0].screenX;
touchendY = e.changedTouches[0].screenY;
checkDirection();
});
}
document.getElementById("history").addEventListener("click", () => {
downloadHistory();
function checkDirection() {
if (touchendX < touchstartX) {
// Swipe Left
}
if (touchendX > touchstartX) {
// Swipe Right
}
if (touchendY < touchstartY) {
volumeUp();
}
if (touchendY > touchstartY) {
volumeDown();
}
}
function openDialog() {
modalEl.classList.add("open");
}
async function getMusic() {
const res = await fetch(
`https://retrowave.ru/api/v1/tracks?limit=10&cursor=${cursor}`
).then((res) => res.json());
const {
body: { tracks, cursor: currentCursor },
} = res;
cursor = currentCursor;
currentTracks = tracks;
}
function initPlayer() {}
function playMusic() {
const currentTrack = currentTracks[0];
const singleTrack = currentTrack.streamUrl;
const fullTrack = `${retroWaveRu}${singleTrack}`;
howlerInstance = new Howl({
src: [fullTrack],
html5: true,
onend: function () {
playNextTrack();
},
});
setVolume();
isPlaying = true;
window.hw = howlerInstance;
document.addEventListener("keyup", (event) => {
const { key } = event;
console.log("key pressed", key);
switch (key) {
case " ":
togglePlay();
break;
case "a":
break;
case "d":
break;
case "w":
volumeUp();
break;
case "s":
volumeDown();
break;
case "n":
playNextTrack();
break;
updateInfo(currentTrack);
}
});
addToHistory(currentTrack);
howlerInstance.play();
}
let touchstartX = 0;
let touchendX = 0;
let touchstartY = 0;
let touchendY = 0;
const musixPlayerEl = document.getElementsByClassName("music-player")[0];
if (musixPlayerEl) {
musixPlayerEl.addEventListener("touchstart", (e) => {
touchstartX = e.changedTouches[0].screenX;
touchstartY = e.changedTouches[0].screenY;
});
musixPlayerEl.addEventListener("touchend", (e) => {
touchendX = e.changedTouches[0].screenX;
touchendY = e.changedTouches[0].screenY;
checkDirection();
});
function volumeDown() {
if (volume > 0.1) {
volume -= 0.1;
}
setVolume();
}
function checkDirection() {
if (touchendX < touchstartX) {
// Swipe Left
}
if (touchendX > touchstartX) {
// Swipe Right
}
if (touchendY < touchstartY) {
volumeUp();
}
if (touchendY > touchstartY) {
volumeDown();
}
function volumeUp() {
if (volume < 1) {
volume += 0.1;
}
setVolume();
}
function openDialog() {
modalEl.classList.add("open");
function setVolume() {
howlerInstance.volume(volume);
}
function togglePlay() {
isPlaying = !isPlaying;
if (isPlaying) {
howlerInstance.play();
} else {
howlerInstance.pause();
}
}
async function getMusic() {
const res = await fetch(
`https://retrowave.ru/api/v1/tracks?limit=10&cursor=${cursor}`
).then((res) => res.json());
const {
body: { tracks, cursor: currentCursor },
} = res;
cursor = currentCursor;
currentTracks = tracks;
}
function updateInfo(trackDetails) {
titleEl.innerText = trackDetails.title;
document.title = `Now Playing... ${trackDetails.title}`;
coverArtEl.style.backgroundImage = `url("${retroWaveRu}${trackDetails.artworkUrl}")`;
ovr.innerHTML = `${trackDetails.title}`
}
function initPlayer() { }
function getHistory() {
let localHistoryStore = localStorage.getItem("retrowave-history") || "[]";
let historyArray = JSON.parse(localHistoryStore);
return historyArray;
}
function playMusic() {
const currentTrack = currentTracks[0];
const singleTrack = currentTrack.streamUrl;
const fullTrack = `${retroWaveRu}${singleTrack}`;
howlerInstance = new Howl({
src: [fullTrack],
html5: true,
onend: function () {
playNextTrack();
},
});
setVolume();
isPlaying = true;
window.hw = howlerInstance
function addToHistory(trackDetails) {
let historyArray = getHistory();
historyArray.push(trackDetails);
localStorage.setItem("retrowave-history", JSON.stringify(historyArray));
}
updateInfo(currentTrack);
addToHistory(currentTrack);
howlerInstance.play();
}
function volumeDown() {
console.log(volume);
if (volume > 0.1) {
volume -= 0.1;
}
setVolume();
}
function volumeUp() {
if (volume < 1) {
volume += 0.1;
}
setVolume();
}
function setVolume() {
howlerInstance.volume(volume);
}
function togglePlay() {
isPlaying = !isPlaying;
if (isPlaying) {
howlerInstance.play();
} else {
howlerInstance.pause();
}
}
function updateInfo(trackDetails) {
titleEl.innerText = trackDetails.title;
document.title = `Now Playing... ${trackDetails.title}`;
coverArtEl.style.backgroundImage = `url("${retroWaveRu}${trackDetails.artworkUrl}")`;
}
function getHistory() {
let localHistoryStore = localStorage.getItem("retrowave-history") || "[]";
let historyArray = JSON.parse(localHistoryStore);
return historyArray;
}
function addToHistory(trackDetails) {
let historyArray = getHistory();
historyArray.push(trackDetails);
localStorage.setItem("retrowave-history", JSON.stringify(historyArray));
}
function downloadHistory() {
const historyArray = getHistory();
let element = document.createElement("a");
let playListData = '#EXTM3U';
historyArray.forEach((musicData) => {
playListData = `${playListData}
function downloadHistory() {
const historyArray = getHistory();
let element = document.createElement("a");
let playListData = "#EXTM3U";
historyArray.forEach((musicData) => {
playListData = `${playListData}
#EXTINF:${Math.ceil(musicData.duration / 1000)}, ${musicData.title}
https://retrowave.ru/${musicData.streamUrl}
`;
});
});
element.setAttribute(
"href",
"data:audio/x-mpegurl;;charset=utf-8," +
encodeURIComponent(playListData)
);
element.setAttribute("download", "retrowave_playlist.m3u");
element.setAttribute(
"href",
"data:audio/x-mpegurl;;charset=utf-8," + encodeURIComponent(playListData)
);
element.setAttribute("download", "retrowave_playlist.m3u");
element.style.display = "none";
document.body.appendChild(element);
element.style.display = "none";
document.body.appendChild(element);
element.click();
element.click();
document.body.removeChild(element);
document.body.removeChild(element);
}
function playNextTrack() {
resetHowler();
currentTracks.shift();
if (currentTracks.length <= 3) {
getMusic();
}
playMusic();
}
function playNextTrack() {
resetHowler();
currentTracks.shift();
if (currentTracks.length <= 3) {
getMusic();
}
playMusic();
function resetHowler(destroy = false) {
howlerInstance.stop();
if (destroy) {
howlerInstance.unload();
howlerInstance = null;
}
}
function resetHowler(destroy = false) {
howlerInstance.stop();
if (destroy) {
howlerInstance.unload();
howlerInstance = null;
}
function initControls() {
refreshBtn.addEventListener("click", () => {
playNextTrack();
});
fullScreenBtn.addEventListener("click", () => {
toggleFullScreen();
});
}
function toggleFullScreen() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
}
}
}
function initControls() {
refreshBtn.addEventListener("click", () => {
playNextTrack();
});
}
// function initCodef() {
// const width = window.innerWidth;
// const height = window.innerHeight;
// effectCanvas = new canvas(width, height, 'codef-canvas');
// starField = new starfield3D(effectCanvas, 500, 2, width, height, width/2, height/2, '#ffffff', 100, 0, 0);
// line3D = new codef3D(effectCanvas, 320, 75, 1, 1500 );
// line3D.line({x:-320, y:0, z:0},{x:320, y:0, z:0}, new LineBasicMaterial({ color: synthwaveColor, linewidth:2}));
// line3D.line({x: 0, y:-240, z:0},{x:0, y:240, z:0}, new LineBasicMaterial({ color: synthwaveColor, linewidth:2}));
// renderCodeFx();
// }
// function renderCodeFx() {
// effectCanvas.fill('#000000');
// line3D.group.rotation.x+=0.01;
// line3D.group.rotation.y+=0.02;
// line3D.group.rotation.z+=0.04;
// starField.draw();
// line3D.draw();
// requestAnimationFrame(renderCodeFx);
// }
function initHydra() {
voronoi(350, 0.15)
.modulateScale(osc(8).rotate(Math.sin(time)), .5)
.thresh(.8)
.modulateRotate(osc(7), .4)
.thresh(.7)
.diff(src(o0).scale(1.8))
.modulateScale(osc(2).modulateRotate(o0, .74))
.diff(src(o0).rotate([-.012, .01, -.002, 0]).scrollY(0, [-1 / 199800, 0].fast(0.7)))
.brightness([-.02, -.17].smooth().fast(.5))//.modulate(o0, () => a.fft[1] * .2)
.out()
function toggleControls() {
const toggleableElements = document.querySelectorAll(".toggleable");
toggleableElements.forEach((el) => {
el.classList.toggle("hidden");
});
}
function toggleEverything() {
musixPlayerEl.classList.toggle("hidden");
ovr.classList.toggle("hidden");
}
// function initCodef() {
// const width = window.innerWidth;
// const height = window.innerHeight;
// effectCanvas = new canvas(width, height, 'codef-canvas');
// starField = new starfield3D(effectCanvas, 500, 2, width, height, width/2, height/2, '#ffffff', 100, 0, 0);
// line3D = new codef3D(effectCanvas, 320, 75, 1, 1500 );
// line3D.line({x:-320, y:0, z:0},{x:320, y:0, z:0}, new LineBasicMaterial({ color: synthwaveColor, linewidth:2}));
// line3D.line({x: 0, y:-240, z:0},{x:0, y:240, z:0}, new LineBasicMaterial({ color: synthwaveColor, linewidth:2}));
// renderCodeFx();
// }
// function renderCodeFx() {
// effectCanvas.fill('#000000');
// line3D.group.rotation.x+=0.01;
// line3D.group.rotation.y+=0.02;
// line3D.group.rotation.z+=0.04;
// starField.draw();
// line3D.draw();
// requestAnimationFrame(renderCodeFx);
// }
function initHydra() {
try {
voronoi(350, 0.15)
.modulateScale(osc(8).rotate(Math.sin(time)), 0.5)
.thresh(0.8)
.modulateRotate(osc(7), 0.4)
.thresh(0.7)
.diff(src(o0).scale(1.8))
.modulateScale(osc(2).modulateRotate(o0, 0.74))
.diff(
src(o0)
.rotate([-0.012, 0.01, -0.002, 0])
.scrollY(0, [-1 / 199800, 0].fast(0.7))
)
.brightness([-0.02, -0.17].smooth().fast(0.5)) //.modulate(o0, () => a.fft[1] * .2)
.out();
} catch (error) {
console.error("Hydra initialization failed:", error);
}
}
})();