Transaction

c73ffd8f331fa013280d2f97f51ea09256274a6525f2ebead19bf8db4e39ecef
Timestamp (utc)
2025-02-11 09:25:45
Fee Paid
0.00000240 BSV
(
0.00980013 BSV
-
0.00979773 BSV
)
Fee Rate
10.01 sat/KB
Version
1
Confirmations
51,585
Size Stats
23,954 B

2 Outputs

Total Output:
0.00979773 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, maximum-scale=1.0, user-scalable=no"> <title>Interactive Glitch Art with Magical Effects</title> <style> body { margin: 0; overflow: hidden; background: #000; touch-action: none; } canvas { display: block; } #info { position: absolute; bottom: 10px; left: 10px; color: #ffffff; font-family: monospace; background: rgba(0, 0, 0, 0.7); padding: 10px; border-radius: 5px; font-size: 12px; } @media screen and (max-width: 1024px) { #info { font-size: 8px; } } @media screen and (max-width: 320px) { #info { font-size: 6px; } } @media (hover: none) and (pointer: coarse) { .desktop-guide { display: none; } } @media (hover: hover) and (pointer: fine) { .mobile-guide { display: none; } } #colorPalette { display: flex; flex-wrap: wrap; margin-top: 10px; gap: 4px; } .colorSwatch { width: 20px; height: 20px; border: 1px solid #fff; border-radius: 3px; } </style> </head> <body> <canvas id="artCanvas"></canvas> <div id="info"></div> <script> const canvas = document.getElementById('artCanvas'); const ctx = canvas.getContext('2d'); // State variables let currentBlockHash = ''; let currentBlockHeight = 0; let lastUpdateTime = 0; const updateInterval = 60000; let squares = []; let isGlitching = false; let glitchInterval; let originalSquares = []; let noiseCanvas; let noiseCtx; let noiseData; let particles = []; let lastMouseX = null; let lastMouseY = null; let lastTouchX = null; let lastTouchY = null; let isTouching = false; // Glitch configuration const glitchConfig = { noiseIntensity: 30, // ノイズの強度 - 値を大きくするとより激しいノイズになります noiseSpeed: 0.1, // ノイズの変化速度 noiseDensity: 100, // ノイズの密度 glitchProbability: 0.3, // スクエアがグリッチする確率 - 値を大きくすると、より頻繁にグリッチが発生します intervalMin: 50, // グリッチ間の最小インターバル intervalMax: 200, // グリッチ間の最大インターバル offsetMax: 15, // スクエアの最大ずれ距離 - 値を大きくするとスクエアがより大きくずれます colorShiftProbability: 0.3 // 色がシフトする確率 - 値を大きくすると、色の変化がより頻繁に起こります }; // Particle class with enhanced effects class Particle { constructor(x, y) { this.x = x; this.y = y; this.size = Math.random() * 6 + 4; // サイズを大きく (4-10) // より複雑な動きのための速度設定 const speed = Math.random() * 2 + 1; const angle = Math.random() * Math.PI * 2; this.speedX = Math.cos(angle) * speed; this.speedY = Math.sin(angle) * speed; // より長い寿命 this.life = 1.0; this.fadeSpeed = 0.02; // ゆっくりフェードアウト // 白い絵具のような色設定 this.baseColor = this.generateWhitePaintColor(); this.color = this.baseColor; // キラキラエフェクトのための追加プロパティ this.glowSize = this.size * 2; this.pulseSpeed = Math.random() * 0.05 + 0.02; this.pulsePhase = Math.random() * Math.PI * 2; // テクスチャの追加 this.textureOffset = Math.random() * 1000; } generateWhitePaintColor() { // 白い絵具の微妙な色のバリエーション const variation = Math.random() * 10; return `hsl(0, 0%, ${85 + variation}%)`; } update() { // 位置の更新 this.x += this.speedX; this.y += this.speedY; // 徐々に減速 this.speedX *= 0.99; this.speedY *= 0.99; // 寿命の更新 this.life -= this.fadeSpeed; // テクスチャの変化 this.textureOffset += 0.1; // サイズの脈動 const pulse = Math.sin(this.pulsePhase) * 0.3 + 0.7; this.pulsePhase += this.pulseSpeed; } draw(ctx) { ctx.save(); // 白い絵具のグローエフェクト const gradient = ctx.createRadialGradient( this.x, this.y, 0, this.x, this.y, this.glowSize ); gradient.addColorStop(0, `hsla(0, 0%, 100%, ${this.life * 0.3})`); gradient.addColorStop(1, `hsla(0, 0%, 100%, 0)`); ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(this.x, this.y, this.glowSize, 0, Math.PI * 2); ctx.fill(); // テクスチャの追加(紙のようなざらざらした質感) const noiseIntensity = Math.sin(this.textureOffset) * 10; // メインのパーティクル ctx.fillStyle = this.generateWhitePaintColor(); ctx.globalAlpha = this.life * (0.7 + noiseIntensity * 0.01); ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); // 紙のテクスチャを模倣 ctx.shadowBlur = 3; ctx.shadowColor = 'rgba(0,0,0,0.1)'; ctx.fill(); // キラキラエフェクト(十字の光) ctx.strokeStyle = `hsla(0, 0%, 100%, ${this.life * 0.3})`; ctx.lineWidth = 1; // 水平の線 ctx.beginPath(); ctx.moveTo(this.x - this.size * 1.5, this.y); ctx.lineTo(this.x + this.size * 1.5, this.y); ctx.stroke(); // 垂直の線 ctx.beginPath(); ctx.moveTo(this.x, this.y - this.size * 1.5); ctx.lineTo(this.x, this.y + this.size * 1.5); ctx.stroke(); ctx.restore(); } } function setup() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; setupNoiseCanvas(); updateArt(); } function setupNoiseCanvas() { noiseCanvas = document.createElement('canvas'); noiseCanvas.width = canvas.width; noiseCanvas.height = canvas.height; noiseCtx = noiseCanvas.getContext('2d'); noiseData = noiseCtx.createImageData(canvas.width, canvas.height); } function generateNoise() { const data = noiseData.data; for (let i = 0; i < data.length; i += 4) { const noise = Math.random() * glitchConfig.noiseIntensity; data[i] = noise; data[i + 1] = noise; data[i + 2] = noise; data[i + 3] = Math.random() * 255; } noiseCtx.putImageData(noiseData, 0, 0); } function draw() { ctx.fillStyle = '#0000FF'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeStyle = '#ffffff'; ctx.lineWidth = 10; ctx.strokeRect(5, 5, canvas.width - 10, canvas.height - 10); squares.forEach(square => { if (!square.shattered) { if (isGlitching) { drawGlitchedSquare(square); } else { drawRoundedSquare(square.x, square.y, square.size, square.color, square.cornerRadius); } } else { drawShatteredSquare(square); } updateSquarePosition(square); }); // パーティクルの更新と描画 particles = particles.filter(particle => { particle.update(); if (particle.life > 0 && particle.size > 0) { particle.draw(ctx); return true; } return false; }); if (isGlitching) { generateNoise(); ctx.globalCompositeOperation = 'overlay'; ctx.drawImage(noiseCanvas, 0, 0); ctx.globalCompositeOperation = 'source-over'; } requestAnimationFrame(draw); } function drawRoundedSquare(x, y, size, color, radius) { ctx.beginPath(); ctx.moveTo(x + radius, y); ctx.lineTo(x + size - radius, y); ctx.quadraticCurveTo(x + size, y, x + size, y + radius); ctx.lineTo(x + size, y + size - radius); ctx.quadraticCurveTo(x + size, y + size, x + size - radius, y + size); ctx.lineTo(x + radius, y + size); ctx.quadraticCurveTo(x, y + size, x, y + size - radius); ctx.lineTo(x, y + radius); ctx.quadraticCurveTo(x, y, x + radius, y); ctx.closePath(); ctx.fillStyle = color; ctx.globalAlpha = 0.7; ctx.fill(); ctx.globalAlpha = 1; } function drawGlitchedSquare(square) { const glitched = applyGlitchEffect(square); drawRoundedSquare( glitched.x, glitched.y, glitched.size, glitched.color, glitched.cornerRadius ); } function applyGlitchEffect(square) { const glitched = { ...square }; if (Math.random() < glitchConfig.glitchProbability) { glitched.x += (Math.random() * 2 - 1) * glitchConfig.offsetMax; glitched.y += (Math.random() * 2 - 1) * glitchConfig.offsetMax; if (Math.random() < glitchConfig.colorShiftProbability) { const hslMatch = glitched.color.match(/hsl\((\d+),\s*(\d+)%,\s*(\d+)%\)/); if (hslMatch) { const [_, h, s, l] = hslMatch.map(Number); const shiftedHue = (h + Math.floor(Math.random() * 30) - 15) % 360; glitched.color = `hsl(${shiftedHue}, ${s}%, ${l}%)`; } } } return glitched; } function drawShatteredSquare(square) { square.fragments.forEach(fragment => { ctx.fillStyle = fragment.color; ctx.fillRect(fragment.x, fragment.y, fragment.size, fragment.size); fragment.x += fragment.vx; fragment.y += fragment.vy; }); } function updateSquarePosition(square) { if (!square.shattered) { square.x += square.vx; square.y += square.vy; if (square.x + square.size > canvas.width || square.x < 0) { square.vx *= -1; } if (square.y + square.size > canvas.height || square.y < 0) { square.vy *= -1; } } } function improvedGenerateSquares(blockHash) { const squares = []; const hashParts = blockHash.match(/.{1,2}/g) || []; for (let i = 0; i < 10; i++) { for (let j = 0; j < 10; j++) { const partIndex = (i * 10 + j) % hashParts.length; const part = hashParts[partIndex]; const sizeValue = parseInt(part, 16) / 255; const size = 25 + 175 * (1 - Math.exp(-3 * sizeValue)); const colorValue = parseInt(hashParts[(partIndex + 1) % hashParts.length], 16) / 255; const hue = colorValue * 360; const color = `hsl(${hue}, 70%, 80%)`; const x = (i / 10) * canvas.width; const y = (j / 10) * canvas.height; const cornerRadius = size / 4; const vx = (Math.random() - 0.5) * 2; const vy = (Math.random() - 0.5) * 2; squares.push({ x, y, size, color, cornerRadius, vx, vy, shattered: false, fragments: [] }); } } return squares.sort((a, b) => b.size - a.size); } function shatterSquare(square) { const fragmentSize = square.size / 10; square.fragments = []; for (let i = 0; i < 10; i++) { for (let j = 0; j < 10; j++) { square.fragments.push({ x: square.x + i * fragmentSize, y: square.y + j * fragmentSize, size: fragmentSize, color: square.color, vx: (Math.random() - 0.5) * 4, vy: (Math.random() - 0.5) * 4 }); } } square.shattered = true; } function shatterAllSquares() { squares.forEach(square => shatterSquare(square)); setTimeout(() => { squares.forEach(square => { square.shattered = false; square.fragments = []; }); }, 3000); } function toggleGlitchMode() { isGlitching = !isGlitching; if (isGlitching) { originalSquares = JSON.parse(JSON.stringify(squares)); startGlitchEffect(); if (navigator.vibrate) { navigator.vibrate(100); } } else { stopGlitchEffect(); squares = originalSquares; } } function startGlitchEffect() { glitchInterval = setInterval(() => { squares = originalSquares.map(square => Math.random() < 0.3 ? { ...square } : square ); }, Math.random() * (glitchConfig.intervalMax - glitchConfig.intervalMin) + glitchConfig.intervalMin); } function stopGlitchEffect() { clearInterval(glitchInterval); } function createParticles(startX, startY, endX, endY) { if (startX === null || startY === null) return; const distance = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2)); const particleCount = Math.floor(distance / 3); // より密度の高いパーティクル生成 for (let i = 0; i < particleCount; i++) { const ratio = i / particleCount; const x = startX + (endX - startX) * ratio; const y = startY + (endY - startY) * ratio; // メインのパーティクル particles.push(new Particle(x, y)); // 装飾的な追加パーティクル if (Math.random() < 0.5) { // 50%の確率で追加パーティクル const decorativeParticle = new Particle( x + (Math.random() * 20 - 10), y + (Math.random() * 20 - 10) ); particles.push(decorativeParticle); } } } function xorHexStrings(hex1, hex2) { const buf1 = new Uint8Array(hex1.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); const buf2 = new Uint8Array(hex2.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); const result = new Uint8Array(buf1.length); for (let i = 0; i < buf1.length; i++) { result[i] = buf1[i] ^ buf2[i]; } return Array.from(result, byte => byte.toString(16).padStart(2, '0')).join(''); } function preprocessHash(blockHash) { const fixedString = "f".repeat(blockHash.length); return xorHexStrings(blockHash, fixedString); } function handleMouseMove(e) { const pos = getPosition(e); if (lastMouseX !== null && lastMouseY !== null) { createParticles(lastMouseX, lastMouseY, pos.x, pos.y); } lastMouseX = pos.x; lastMouseY = pos.y; } function handleMouseLeave() { lastMouseX = null; lastMouseY = null; } function handleTouchStart(e) { if (e.touches.length === 2) { e.preventDefault(); toggleGlitchMode(); } else if (e.touches.length === 1) { e.preventDefault(); isTouching = true; const touch = e.touches[0]; const pos = getPosition(touch); lastTouchX = pos.x; lastTouchY = pos.y; } } function handleTouchMove(e) { e.preventDefault(); if (e.touches.length === 1 && isTouching) { const touch = e.touches[0]; const pos = getPosition(touch); createParticles(lastTouchX, lastTouchY, pos.x, pos.y); lastTouchX = pos.x; lastTouchY = pos.y; } } function handleTouchEnd() { isTouching = false; lastTouchX = null; lastTouchY = null; } function getPosition(e) { const rect = canvas.getBoundingClientRect(); return { x: e.clientX - rect.left, y: e.clientY - rect.top }; } async function fetchBlockInfo() { try { const response = await fetch('/v1/bsv/block/latest'); if (!response.ok) throw new Error('Network response was not ok'); const data = await response.json(); return { hash: data.hash, height: data.height }; } catch (error) { console.error('Error fetching block info:', error); document.getElementById('info').innerHTML = 'Error fetching block info'; return null; } } function updateArt() { fetchBlockInfo().then(blockInfo => { if (blockInfo && blockInfo.hash !== currentBlockHash) { currentBlockHash = blockInfo.hash; currentBlockHeight = blockInfo.height; shatterAllSquares(); setTimeout(() => { const processedHash = preprocessHash(blockInfo.hash); squares = improvedGenerateSquares(processedHash); displayBlockInfo(blockInfo.hash, blockInfo.height); }, 3000); } }).catch(error => { console.error('Error updating art:', error); }); } function displayBlockInfo(blockHash, blockHeight) { const colorPalette = generateColorPalette(); document.getElementById('info').innerHTML = ` <div>Block Height: ${blockHeight}</div> <div>Block Hash: ${blockHash}</div> <div>Youth Colors:</div> <div id="colorPalette">${colorPalette}</div> <div style="margin-top: 10px;"> <span class="desktop-guide">Press G to toggle glitch effect</span> <span class="mobile-guide">Two-finger tap to toggle glitch effect</span> </div> `; } function generateColorPalette() { const uniqueColors = [...new Set(squares.map(square => square.color))]; return uniqueColors.map(color => `<div class="colorSwatch" style="background-color: ${color};" title="${color}"></div>` ).join(''); } // Initialize controls function initializeControls() { // キーボードハンドラー document.addEventListener('keydown', (event) => { if (event.key === 'g' || event.key === 'G') { toggleGlitchMode(); } }); // マウス用のイベントリスナー canvas.addEventListener('mousemove', handleMouseMove); canvas.addEventListener('mouseleave', handleMouseLeave); // タッチ操作用のイベントリスナー canvas.addEventListener('touchstart', handleTouchStart); canvas.addEventListener('touchmove', handleTouchMove); canvas.addEventListener('touchend', handleTouchEnd); // 四角形をクリックした時の破壊エフェクト canvas.addEventListener('click', (event) => { const rect = canvas.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; squares.forEach(square => { if (x > square.x && x < square.x + square.size && y > square.y && y < square.y + square.size) { shatterSquare(square); setTimeout(() => { square.shattered = false; square.fragments = []; }, 3000); } }); }); } // Window resize handler window.addEventListener('resize', () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; setupNoiseCanvas(); particles = []; // パーティクルをクリア const processedHash = preprocessHash(currentBlockHash); squares = improvedGenerateSquares(processedHash); }); // Initialize everything setInterval(updateArt, updateInterval); setup(); initializeControls(); draw(); </script> </body> </html>hv© £üaÍïêjj&@Ú:‹ø'šÀ_ψ¬
    https://whatsonchain.com/tx/c73ffd8f331fa013280d2f97f51ea09256274a6525f2ebead19bf8db4e39ecef