#0
0.00000001 BSV
v© tÝWÎ<ÖÖ{7tNy.¬ cordQ text/html Mf%<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>BSV Chain Ocean Dynamics</title>
<style>
body { margin: 0; padding: 0; overflow: hidden; background-color: #E6F3FF; }
canvas { display: block; }
#startButton {
position: absolute;
top: 20px;
left: 20px;
padding: 10px;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
font-size: 16px;
}
#blockInfo {
position: absolute;
bottom: 20px;
left: 20px;
color: #003366;
font-family: Arial, sans-serif;
background: rgba(255,255,255,0.7);
padding: 15px;
border-radius: 5px;
font-size: 14px;
line-height: 1.5;
transition: all 0.3s ease;
}
</style>
</head>
<body>
<canvas id="oceanCanvas"></canvas>
<button id="startButton">Start Ocean Dynamics</button>
<div id="blockInfo"></div>
<script>
const API_ENDPOINT = 'https://api.whatsonchain.com/v1/bsv/main';
const canvas = document.getElementById('oceanCanvas');
const ctx = canvas.getContext('2d');
let audioContext;
let isAudioInitialized = false;
let currentBlockHeight = 0;
let waveParams = { amplitude: 20, frequency: 0.02, speed: 0.05 };
let colorPalette = ['#0077BE', '#0099CC', '#00BFFF', '#87CEEB', '#B0E0E6'];
function init() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
animate();
canvas.addEventListener('click', handleInteraction);
canvas.addEventListener('touchstart', handleInteraction);
document.getElementById('startButton').addEventListener('click', initAudioAndPlay);
fetchBlockInfo();
setInterval(fetchBlockInfo, 60000);
}
function initAudioAndPlay() {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
isAudioInitialized = true;
document.getElementById('startButton').style.display = 'none';
playOceanSound();
}
function animate() {
ctx.fillStyle = '#E6F3FF';
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawWaves();
requestAnimationFrame(animate);
}
function drawWaves() {
for (let i = 0; i < colorPalette.length; i++) {
ctx.beginPath();
ctx.moveTo(0, canvas.height);
for (let x = 0; x < canvas.width; x++) {
let y = Math.sin(x * waveParams.frequency + Date.now() * waveParams.speed + i * 0.5)
* waveParams.amplitude * (1 - i * 0.1) + i * 10;
y += canvas.height - colorPalette.length * 20;
ctx.lineTo(x, y);
}
ctx.lineTo(canvas.width, canvas.height);
ctx.closePath();
ctx.fillStyle = colorPalette[i];
ctx.fill();
}
}
function handleInteraction(event) {
event.preventDefault();
const rect = canvas.getBoundingClientRect();
const x = (event.clientX || event.touches[0].clientX) - rect.left;
const y = (event.clientY || event.touches[0].clientY) - rect.top;
createRipple(x, y);
playWaterDropSound();
}
function createRipple(x, y) {
let ripple = {
x: x,
y: y,
radius: 0,
maxRadius: 100,
alpha: 1,
color: colorPalette[Math.floor(Math.random() * colorPalette.length)]
};
function drawRipple() {
ctx.strokeStyle = `${ripple.color}${Math.floor(ripple.alpha * 255).toString(16).padStart(2, '0')}`;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(ripple.x, ripple.y, ripple.radius, 0, Math.PI * 2);
ctx.stroke();
ripple.radius += 3;
ripple.alpha -= 0.02;
if (ripple.alpha > 0) {
requestAnimationFrame(drawRipple);
}
}
drawRipple();
}
function playWaterDropSound() {
if (!isAudioInitialized) return;
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(400, audioContext.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(20, audioContext.currentTime + 0.5);
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.5);
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.start();
oscillator.stop(audioContext.currentTime + 0.5);
}
function playOceanSound() {
if (!isAudioInitialized) return;
const bufferSize = audioContext.sampleRate * 5;
const noiseBuffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate);
const output = noiseBuffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
output[i] = Math.random() * 2 - 1;
}
const whiteNoise = audioContext.createBufferSource();
whiteNoise.buffer = noiseBuffer;
whiteNoise.loop = true;
const bandpass = audioContext.createBiquadFilter();
bandpass.type = 'bandpass';
bandpass.frequency.value = 400;
bandpass.Q.value = 0.5;
const gainNode = audioContext.createGain();
gainNode.gain.setValueAtTime(0.05, audioContext.currentTime);
whiteNoise.connect(bandpass);
bandpass.connect(gainNode);
gainNode.connect(audioContext.destination);
whiteNoise.start();
}
async function fetchBlockInfo() {
try {
const response = await fetch(`${API_ENDPOINT}/chain/info`);
if (!response.ok) throw new Error('Network response was not ok');
const chainInfo = await response.json();
const blockResponse = await fetch(`${API_ENDPOINT}/block/${chainInfo.bestblockhash}`);
if (!blockResponse.ok) throw new Error('Network response was not ok');
const blockData = await blockResponse.json();
if (blockData.height !== currentBlockHeight) {
currentBlockHeight = blockData.height;
updateOceanDynamics(blockData);
displayBlockInfo(blockData);
}
} catch (error) {
console.error('Error fetching block info:', error);
}
}
function updateOceanDynamics(blockData) {
const txCount = blockData.tx.length;
waveParams.amplitude = Math.min(50, Math.max(10, txCount / 10));
waveParams.frequency = Math.min(0.05, Math.max(0.01, txCount / 5000));
waveParams.speed = Math.min(0.1, Math.max(0.02, txCount / 2000));
// Adjust blue shades based on transaction count
const baseBlue = Math.min(255, Math.max(100, 150 + txCount / 10));
colorPalette = [
`rgb(0, ${baseBlue - 50}, ${baseBlue})`,
`rgb(0, ${baseBlue - 25}, ${baseBlue})`,
`rgb(0, ${baseBlue}, ${baseBlue})`,
`rgb(${baseBlue - 50}, ${baseBlue}, ${baseBlue})`,
`rgb(${baseBlue - 25}, ${baseBlue}, ${baseBlue})`
];
if (isAudioInitialized) {
updateOceanSound(txCount);
}
}
function updateOceanSound(txCount) {
const bandpass = audioContext.createBiquadFilter();
bandpass.type = 'bandpass';
bandpass.frequency.setValueAtTime(200 + txCount, audioContext.currentTime);
bandpass.Q.setValueAtTime(0.5 + (txCount / 1000), audioContext.currentTime);
}
function displayBlockInfo(blockData) {
const blockInfo = document.getElementById('blockInfo');
const timestamp = new Date(blockData.time * 1000).toLocaleString();
blockInfo.innerHTML = `
<div><strong>Block Height:</strong> ${blockData.height}</div>
<div><strong>Transactions:</strong> ${blockData.tx.length}</div>
<div><strong>Block Size:</strong> ${(blockData.size / 1024).toFixed(2)} KB</div>
<div><strong>Timestamp:</strong> ${timestamp}</div>
<div><strong>Difficulty:</strong> ${blockData.difficulty.toFixed(2)}</div>
`;
blockInfo.style.transform = 'scale(1.05)';
setTimeout(() => {
blockInfo.style.transform = 'scale(1)';
}, 300);
}
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
});
init();
</script>
</body>
</html>h
https://whatsonchain.com/tx/0caead28d2c114ab2d7ed82c96e1c9835b47a6fe413dfd8ec0076eed2fc34181