Transaction

c761a95a47fc5d68d5a4e113f3f0fc162e851517b4e413b2b21d3f1079d10fc4
Timestamp (utc)
2025-02-11 12:09:38
Fee Paid
0.00000244 BSV
(
0.00977772 BSV
-
0.00977528 BSV
)
Fee Rate
10.03 sat/KB
Version
1
Confirmations
51,217
Size Stats
24,315 B

2 Outputs

Total Output:
0.00977528 BSV
  • cordQ text/htmlM^<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>BSViewer SoyBlack</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; color: #000; margin: 0; padding: 0; min-height: 100vh; overflow: auto; background: #000; display: flex; justify-content: center; align-items: center; } .wrapper { position: relative; width: 100%; max-width: 90vh; margin: 0 auto; aspect-ratio: 1/1; } .background { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: url('https://ordfs.network/content/5a019218b29bd9bfac062105ea82c8106525386c3761406bdc7466391f3e6ce4_0'); background-size: contain; background-position: center; background-repeat: no-repeat; } #particle-canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; filter: blur(1px); } .container { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: flex-start; z-index: 2; padding-top: 15%; } .info-card { background: transparent; width: 25%; aspect-ratio: 1/1; padding: 20px; display: flex; flex-direction: column; justify-content: center; align-items: center; transform: perspective(1000px) rotateX(5deg); transform-origin: center; } .title { font-size: min(2vw, 24px); font-weight: bold; text-align: center; margin-bottom: 10px; color: #333; } .info-grid { display: grid; gap: 0; flex: 1; grid-template-rows: repeat(2, min-content); align-items: start; width: 100%; line-height: 0.8; } .info-item { padding: 0; background: transparent; border: none; text-align: center; line-height: 0.8; position: relative; } .info-label { color: #000; font-size: min(1.7vw, 20px); margin: 0; text-transform: uppercase; font-weight: bold; line-height: 1; text-shadow: 0 0 1px rgba(255, 255, 255, 0.5); } .info-value { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: min(2.7vw, 32px); font-weight: bold; line-height: 1; color: #00f7ff; text-shadow: 0 0 10px rgba(0, 247, 255, 0.5), 0 0 20px rgba(0, 247, 255, 0.3), 0 0 30px rgba(0, 247, 255, 0.1); margin: 0; padding-left: 20%; } #status { position: absolute; top: -15px; right: 15px; font-size: min(1vw, 12px); color: #fff; } .updating { color: #00f7ff !important; } @media (orientation: landscape) and (max-height: 500px) { .wrapper { max-width: 90vh; height: 90vh; } } @media (orientation: portrait) { .wrapper { max-width: 90vw; height: 90vw; } .info-card { width: 35%; } } </style> </head> <body> <div class="wrapper"> <canvas id="particle-canvas"></canvas> <div class="background"></div> <div class="container"> <div class="info-card"> <div class="info-grid"> <div class="info-item"> <div class="info-label">Block Height</div> <div id="blockHeight" class="info-value">Loading...</div> <div id="status">Last updated: Never</div> </div> <div class="info-item"> <div class="info-label">Transactions</div> <div id="txCount" class="info-value">Loading...</div> </div> </div> </div> </div> </div> <script> class SoundSynthesizer { constructor() { // Audio context and fundamental sound configuration this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); this.isInitialized = false; // Base frequency (C4 = 261.63Hz) this.baseFreq = 261.63; // Melodic scale (C major pentatonic + additional notes) this.scale = [ this.baseFreq, // C this.baseFreq * 9/8, // D this.baseFreq * 5/4, // E this.baseFreq * 3/2, // G this.baseFreq * 5/3, // A this.baseFreq * 2 // C ]; // Melodic patterns for generating sequences this.melodyPatterns = { pattern1: [0, 2, 4, 2, 1, 2, 4, 2], pattern2: [0, 1, 2, 4, 4, 2, 1, 0], pattern3: [0, 2, 1, 3, 2, 4, 3, 5], pattern4: [4, 2, 0, 2, 4, 2, 1, 2] }; // Chord presets this.chordPresets = { major: [1, 5/4, 3/2], sus4: [1, 4/3, 3/2], major7: [1, 5/4, 3/2, 15/8], add9: [1, 5/4, 3/2, 9/4] }; } // Initialize audio context and start background sounds async initialize() { if (this.isInitialized) return; await this.audioContext.resume(); this.isInitialized = true; await this.createReverb(); this.startBackgroundSound(); } // Create reverb effect async createReverb() { this.reverb = this.audioContext.createConvolver(); const length = 3; // 3 seconds of reverb const decay = 2.5; const sampleRate = this.audioContext.sampleRate; const impulse = this.audioContext.createBuffer(2, length * sampleRate, sampleRate); for (let channel = 0; channel < 2; channel++) { const impulseData = impulse.getChannelData(channel); for (let i = 0; i < impulseData.length; i++) { const t = i / sampleRate; impulseData[i] = (Math.random() * 2 - 1) * Math.exp(-t * decay); } } this.reverb.buffer = impulse; } // Generate melody from block hash generateMelodyFromHash(hash) { const usableHash = hash.replace(/^0+/, ''); const notes = []; // Generate 8 notes from hash for (let i = 0; i < 8; i++) { const value = parseInt(usableHash.substr(i * 2, 2), 16); const noteIndex = value % this.scale.length; notes.push(this.scale[noteIndex]); } return notes; } // Start background ambient sound startBackgroundSound() { // Clear existing sequencer if (this.sequencerInterval) { clearInterval(this.sequencerInterval); } // Melodic background pad const baseFreq = this.baseFreq / 2; // One octave lower this.scale.forEach((freq, index) => { const delay = index * 0.5; // Gradually overlap sounds setTimeout(() => { this.createPadSound(freq / 2, 0.03 / (index + 1)); }, delay * 1000); }); // Start melodic arpeggios this.startMelodicSequence(); } // Create pad sound with LFO and filter createPadSound(frequency, volume) { const osc = this.audioContext.createOscillator(); const gain = this.audioContext.createGain(); const filter = this.audioContext.createBiquadFilter(); // LFO setup const lfo = this.audioContext.createOscillator(); const lfoGain = this.audioContext.createGain(); lfo.type = 'sine'; lfo.frequency.setValueAtTime(0.2 + Math.random() * 0.3, this.audioContext.currentTime); lfoGain.gain.setValueAtTime(frequency * 0.005, this.audioContext.currentTime); // Oscillator setup osc.type = 'sine'; osc.frequency.setValueAtTime(frequency, this.audioContext.currentTime); // Filter setup filter.type = 'lowpass'; filter.frequency.setValueAtTime(frequency * 2, this.audioContext.currentTime); filter.Q.setValueAtTime(0.5, this.audioContext.currentTime); // Connections lfo.connect(lfoGain); lfoGain.connect(osc.frequency); osc.connect(filter); filter.connect(gain); gain.connect(this.reverb); this.reverb.connect(this.audioContext.destination); // Gain setup (smooth fade-in) gain.gain.setValueAtTime(0, this.audioContext.currentTime); gain.gain.linearRampToValueAtTime(volume, this.audioContext.currentTime + 2); // Start osc.start(); lfo.start(); } // Start melodic sequence startMelodicSequence() { let patternIndex = 0; let step = 0; this.sequencerInterval = setInterval(() => { const patterns = Object.values(this.melodyPatterns); const currentPattern = patterns[patternIndex]; const noteIndex = currentPattern[step]; const note = this.scale[noteIndex]; this.playMelodicNote(note); step = (step + 1) % currentPattern.length; if (step === 0) { patternIndex = (patternIndex + 1) % patterns.length; } }, 250); // 16th note at 120 BPM } // Play melodic note playMelodicNote(frequency) { const osc = this.audioContext.createOscillator(); const gain = this.audioContext.createGain(); const filter = this.audioContext.createBiquadFilter(); osc.type = 'sine'; osc.frequency.setValueAtTime(frequency, this.audioContext.currentTime); filter.type = 'bandpass'; filter.frequency.setValueAtTime(frequency, this.audioContext.currentTime); filter.Q.setValueAtTime(2, this.audioContext.currentTime); gain.gain.setValueAtTime(0, this.audioContext.currentTime); gain.gain.linearRampToValueAtTime(0.15, this.audioContext.currentTime + 0.05); gain.gain.exponentialRampToValueAtTime(0.001, this.audioContext.currentTime + 0.3); osc.connect(filter); filter.connect(gain); gain.connect(this.reverb); osc.start(); osc.stop(this.audioContext.currentTime + 0.3); } // Play sound when block is updated playBlockUpdateSound(hash) { this.initialize(); const melodyNotes = this.generateMelodyFromHash(hash); // Play melody notes sequentially melodyNotes.forEach((freq, index) => { setTimeout(() => { const osc = this.audioContext.createOscillator(); const gain = this.audioContext.createGain(); const filter = this.audioContext.createBiquadFilter(); osc.type = 'sine'; osc.frequency.setValueAtTime(freq, this.audioContext.currentTime); filter.type = 'bandpass'; filter.frequency.setValueAtTime(freq, this.audioContext.currentTime); filter.Q.setValueAtTime(2, this.audioContext.currentTime); gain.gain.setValueAtTime(0, this.audioContext.currentTime); gain.gain.linearRampToValueAtTime(0.2, this.audioContext.currentTime + 0.05); gain.gain.exponentialRampToValueAtTime(0.001, this.audioContext.currentTime + 0.5); osc.connect(filter); filter.connect(gain); gain.connect(this.reverb); osc.start(); osc.stop(this.audioContext.currentTime + 0.5); }, index * 200); // Play notes 200ms apart }); // Add chord support const chordBase = melodyNotes[0]; const chordType = Object.values(this.chordPresets)[parseInt(hash.substr(-2), 16) % Object.keys(this.chordPresets).length]; chordType.forEach((ratio, index) => { const osc = this.audioContext.createOscillator(); const gain = this.audioContext.createGain(); const filter = this.audioContext.createBiquadFilter(); osc.type = 'sine'; osc.frequency.setValueAtTime(chordBase * ratio, this.audioContext.currentTime); filter.type = 'lowpass'; filter.frequency.setValueAtTime(chordBase * ratio * 2, this.audioContext.currentTime); filter.Q.setValueAtTime(0.5, this.audioContext.currentTime); gain.gain.setValueAtTime(0, this.audioContext.currentTime); gain.gain.linearRampToValueAtTime(0.1 / (index + 1), this.audioContext.currentTime + 0.1); gain.gain.exponentialRampToValueAtTime(0.001, this.audioContext.currentTime + 2); osc.connect(filter); filter.connect(gain); gain.connect(this.reverb); osc.start(); osc.stop(this.audioContext.currentTime + 2); }); } // Cleanup old sounds cleanupOldSounds() { // Clean up active sounds if (this.activeOscillators) { this.activeOscillators.forEach((osc, index) => { const gain = this.activeGains[index]; gain.gain.exponentialRampToValueAtTime(0.001, this.audioContext.currentTime + 0.1); }); this.activeOscillators = []; this.activeGains = []; } } // Stop all sounds stop() { if (this.sequencerInterval) { clearInterval(this.sequencerInterval); } // Stop background sounds if (this.backgroundOscillators) { this.backgroundOscillators.forEach(osc => osc.stop()); this.backgroundOscillators = []; this.backgroundGains = []; } this.cleanupOldSounds(); } } class Particle { constructor(canvas, hashConfig) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.hashConfig = hashConfig; this.reset(); } reset() { const { hash } = this.hashConfig; // Basic position setup this.x = Math.random() * this.canvas.width; this.y = Math.random() * this.canvas.height; // Size setup (more sparkly impression) this.size = Math.random() * 2 + 0.5; this.baseSize = this.size; // Speed setup (more dynamic) this.speedX = (Math.random() - 0.5) * 1.5; this.speedY = (Math.random() - 0.5) * 1.5; // Sparkle effect parameters this.sparkleSpeed = 0.05 + Math.random() * 0.05; this.sparkleOffset = Math.random() * Math.PI * 2; // Hue setup (blue to light blue range) this.hue = 180 + Math.random() * 40; // 180-220 range this.saturation = 80 + Math.random() * 20; // 80-100% this.brightness = 90 + Math.random() * 10; // 90-100% // Opacity this.alpha = Math.random() * 0.5 + 0.5; this.baseAlpha = this.alpha; } update() { // Position update this.x += this.speedX; this.y += this.speedY; // Sparkle effect update const time = Date.now() * this.sparkleSpeed + this.sparkleOffset; this.size = this.baseSize * (1 + Math.sin(time) * 0.5); this.alpha = this.baseAlpha * (0.8 + Math.sin(time) * 0.2); // Reset position if out of bounds if (this.x < 0 || this.x > this.canvas.width) this.speedX *= -1; if (this.y < 0 || this.y > this.canvas.height) this.speedY *= -1; } draw() { this.ctx.beginPath(); this.ctx.globalAlpha = this.alpha; // Create gradient const gradient = this.ctx.createRadialGradient( this.x, this.y, 0, this.x, this.y, this.size * 2 ); gradient.addColorStop(0, `hsla(${this.hue}, ${this.saturation}%, ${this.brightness}%, 1)`); gradient.addColorStop(0.5, `hsla(${this.hue}, ${this.saturation}%, ${this.brightness}%, 0.3)`); gradient.addColorStop(1, `hsla(${this.hue}, ${this.saturation}%, ${this.brightness}%, 0)`); this.ctx.fillStyle = gradient; this.ctx.arc(this.x, this.y, this.size * 2, 0, Math.PI * 2); this.ctx.fill(); } } class ParticleSystem { constructor(canvasId) { this.canvas = document.getElementById(canvasId); this.ctx = this.canvas.getContext('2d'); this.particles = []; this.particleCount = 65; this.hashConfig = { hash: '0000000000000000000000000000000000000000000000000000000000000000' }; this.resize = this.resize.bind(this); this.animate = this.animate.bind(this); this.updateHashConfig = this.updateHashConfig.bind(this); this.init(); } updateHashConfig(newHash) { this.hashConfig.hash = newHash; // Reset part of the particles when hash changes const resetCount = Math.floor(this.particles.length * 0.2); // Reset 20% of particles for (let i = 0; i < resetCount; i++) { const index = Math.floor(Math.random() * this.particles.length); this.particles[index].reset(); } } init() { window.addEventListener('resize', this.resize); this.resize(); for (let i = 0; i < this.particleCount; i++) { this.particles.push(new Particle(this.canvas, this.hashConfig)); } this.animate(); } resize() { this.canvas.width = this.canvas.offsetWidth; this.canvas.height = this.canvas.offsetHeight; } animate() { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); this.ctx.globalCompositeOperation = 'screen'; this.particles.forEach(particle => { particle.update(); particle.draw(); }); requestAnimationFrame(this.animate); } } let particleSystem; let soundSynthesizer; let lastKnownHeight = null; let isUpdating = false; document.addEventListener('DOMContentLoaded', () => { particleSystem = new ParticleSystem('particle-canvas'); soundSynthesizer = new SoundSynthesizer(); // Try to initialize sound on click (to comply with autoplay restrictions) document.addEventListener('click', () => { soundSynthesizer.initialize(); }); // Attempt autoplay soundSynthesizer.initialize(); }); async function fetchLatestBlock() { if (isUpdating) return; try { isUpdating = true; document.getElementById('status').classList.add('updating'); document.getElementById('status').textContent = 'Updating...'; // タイムアウトを設定 const timeout = 5000; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); try { const heightResponse = await fetch('https://api.whatsonchain.com/v1/bsv/main/chain/info', { signal: controller.signal }); clearTimeout(timeoutId); if (!heightResponse.ok) { throw new Error('Failed to fetch chain info'); } const chainInfo = await heightResponse.json(); const latestHeight = chainInfo.blocks; // データを即座に更新 document.getElementById('blockHeight').textContent = latestHeight; document.getElementById('txCount').textContent = '...'; // バックグラウンドでトランザクション数を取得 fetchTransactionCount(latestHeight); lastKnownHeight = latestHeight; } catch (error) { console.warn('API fetch failed:', error); // エラー時のフォールバック表示 document.getElementById('blockHeight').textContent = '---'; document.getElementById('txCount').textContent = '---'; } } catch (error) { console.error('Critical error:', error); } finally { document.getElementById('status').textContent = ''; document.getElementById('status').classList.remove('updating'); isUpdating = false; } } // 新しい関数: トランザクション数の取得 async function fetchTransactionCount(height) { try { const blockResponse = await fetch(`https://api.whatsonchain.com/v1/bsv/main/block/height/${height}`); if (!blockResponse.ok) throw new Error('Failed to fetch block data'); const blockData = await blockResponse.json(); // パーティクルとサウンドの更新 if (particleSystem) { particleSystem.updateHashConfig(blockData.hash); } if (soundSynthesizer) { soundSynthesizer.playBlockUpdateSound(blockData.hash); } const fullBlockResponse = await fetch(`https://api.whatsonchain.com/v1/bsv/main/block/hash/${blockData.hash}`); if (!fullBlockResponse.ok) throw new Error('Failed to fetch full block data'); const fullBlockData = await fullBlockResponse.json(); document.getElementById('txCount').textContent = fullBlockData.txcount.toLocaleString(); } catch (error) { console.error('Error fetching transaction count:', error); document.getElementById('txCount').textContent = '---'; } } // First execution fetchLatestBlock(); // Update every 5 seconds setInterval(fetchLatestBlock, 10000); // Update when tab becomes visible document.addEventListener('DOMContentLoaded', () => { particleSystem = new ParticleSystem('particle-canvas'); soundSynthesizer = new SoundSynthesizer(); // ユーザーインタラクション後にサウンドを初期化 const initializeSound = async () => { try { await soundSynthesizer.initialize(); // 成功したら、イベントリスナーを削除 document.removeEventListener('click', initializeSound); } catch (error) { console.warn('Sound initialization failed:', error); } }; document.addEventListener('click', initializeSound); // 初回データ取得 fetchLatestBlock(); }); </script> </body> </html> hv© £üaÍïêjj&@Ú:‹ø'šÀ_ψ¬
    https://whatsonchain.com/tx/c761a95a47fc5d68d5a4e113f3f0fc162e851517b4e413b2b21d3f1079d10fc4