318 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			318 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!doctype html>
 | 
						|
 | 
						|
<html lang='en'>
 | 
						|
 | 
						|
<head>
 | 
						|
    <meta charset='utf-8'>
 | 
						|
    <meta content='width=device-width, initial-scale=1, minimum-scale=1' name='viewport'>
 | 
						|
 | 
						|
    <title>vance.land</title>
 | 
						|
    <meta content='vance.land' name='description'>
 | 
						|
    <meta content='vance' name='author'>
 | 
						|
    <base target='_blank'>
 | 
						|
 | 
						|
    <style>
 | 
						|
        @font-face {
 | 
						|
            font-family: 'VT323';
 | 
						|
            src: url('VT323.ttf');
 | 
						|
        }
 | 
						|
 | 
						|
        * {
 | 
						|
            color: #20C20E;
 | 
						|
            font-family: 'VT323', monospace;
 | 
						|
            font-size: 16pt;
 | 
						|
            cursor: none;
 | 
						|
        }
 | 
						|
 | 
						|
        html {
 | 
						|
            width: 100%;
 | 
						|
            height: 100%;
 | 
						|
        }
 | 
						|
 | 
						|
        body {
 | 
						|
            background: #000000;
 | 
						|
            overflow: hidden;
 | 
						|
        }
 | 
						|
 | 
						|
        a {
 | 
						|
            text-decoration: none;
 | 
						|
            white-space: nowrap;
 | 
						|
            overflow: hidden;
 | 
						|
        }
 | 
						|
 | 
						|
        p {
 | 
						|
            padding: 0;
 | 
						|
            margin: 0;
 | 
						|
            font-size: 1rem;
 | 
						|
            white-space: normal;
 | 
						|
            width: 420px;
 | 
						|
        }
 | 
						|
 | 
						|
        span {
 | 
						|
            font-size: 1rem;
 | 
						|
        }
 | 
						|
 | 
						|
        #banana {
 | 
						|
            position: absolute;
 | 
						|
            z-index: 2;
 | 
						|
            pointer-events: none;
 | 
						|
        }
 | 
						|
 | 
						|
        #bonzi {
 | 
						|
            position: absolute;
 | 
						|
            transition: transform 0.8s;
 | 
						|
            transform-style: preserve-3d;
 | 
						|
            z-index: 1;
 | 
						|
            pointer-events: none;
 | 
						|
        }
 | 
						|
 | 
						|
        #live {
 | 
						|
            position: fixed;
 | 
						|
            top: 50%;
 | 
						|
            left: 50%;
 | 
						|
            transform: translate(-50%, -50%);
 | 
						|
            z-index: 0;
 | 
						|
        }
 | 
						|
    </style>
 | 
						|
</head>
 | 
						|
 | 
						|
<body>
 | 
						|
<img alt='banana' id='banana' src='banana.png'/>
 | 
						|
<img alt='bonzi' id='bonzi' src='bonzi.png'/>
 | 
						|
<video autoplay controls height='360px' playsinline id='live' width='640px'>
 | 
						|
</video>
 | 
						|
<script src="https://cdn.jsdelivr.net/npm/hls.js/dist/hls.min.js"></script>
 | 
						|
<script>
 | 
						|
    const email = (function () {
 | 
						|
        var p = Array.prototype.slice.call(arguments),
 | 
						|
            V = p.shift();
 | 
						|
        return p.reverse().map(function (o, i) {
 | 
						|
            return String.fromCharCode(o - V - 36 - i)
 | 
						|
        }).join('')
 | 
						|
    })(59, 164, 200, 197, 207, 193, 213) + (40559).toString(36).toLowerCase() + (function () {
 | 
						|
        var Q = Array.prototype.slice.call(arguments),
 | 
						|
            O = Q.shift();
 | 
						|
        return Q.reverse().map(function (e, u) {
 | 
						|
            return String.fromCharCode(e - O - 57 - u)
 | 
						|
        }).join('')
 | 
						|
    })(20, 125, 179, 176) + (766).toString(36).toLowerCase() + (function () {
 | 
						|
        var E = Array.prototype.slice.call(arguments),
 | 
						|
            f = E.shift();
 | 
						|
        return E.reverse().map(function (s, C) {
 | 
						|
            return String.fromCharCode(s - f - 33 - C)
 | 
						|
        }).join('')
 | 
						|
    })(24, 158, 167);
 | 
						|
 | 
						|
    const socials = {
 | 
						|
        'matrix': {
 | 
						|
            'text': '💊 @vance:vance.land',
 | 
						|
            'link': 'https://matrix.to/#/@vance:vance.land'
 | 
						|
        },
 | 
						|
        'feed': {
 | 
						|
            'text': `🥫 @${email}`,
 | 
						|
            'link': 'https://feed.vance.land/@vance'
 | 
						|
        },
 | 
						|
        'live': {
 | 
						|
            'text': '🎥 live.vance.land',
 | 
						|
            'link': 'https://live.vance.land/vance/'
 | 
						|
        },
 | 
						|
        'email': {
 | 
						|
            'text': `📧 ${email}`,
 | 
						|
            'link': `mailto:${email}`
 | 
						|
        },
 | 
						|
        'urbit': {
 | 
						|
            'text': '🌐 ~sarsup-figput',
 | 
						|
            'link': 'https://sarsup-figput.vance.land/blog'
 | 
						|
        },
 | 
						|
        'telegram': {
 | 
						|
            'text': '💬 @vanceland',
 | 
						|
            'link': 'https://t.me/vanceland'
 | 
						|
        },
 | 
						|
        'code': {
 | 
						|
            'text': '🐱💻 code.vance.land',
 | 
						|
            'link': 'https://code.vance.land/vance'
 | 
						|
        },
 | 
						|
        'music': {
 | 
						|
            'text': '🎶 @SMOOTHAPPLIANCE',
 | 
						|
            'link': 'https://soundcloud.com/smoothappliance'
 | 
						|
        },
 | 
						|
        'haram': {
 | 
						|
            'text': '🕋',
 | 
						|
            'link': 'https://dreamsinco.de'
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    // bonzi
 | 
						|
    const banana = document.getElementById('banana');
 | 
						|
    const bonzi = document.getElementById('bonzi');
 | 
						|
 | 
						|
    let mouseTop = 0;
 | 
						|
    let mouseLeft = 0;
 | 
						|
    let bonziTop = 0;
 | 
						|
    let bonziLeft = 0;
 | 
						|
    const speed = 0.02;
 | 
						|
 | 
						|
    (function moveBonzi() {
 | 
						|
        bonzi.style.transform = bonziLeft > mouseLeft ? 'translate(5%, -35%) scaleX(-1)' : 'translate(-80%, -35%)';
 | 
						|
        bonziTop = bonziTop + ((mouseTop - bonziTop) * speed);
 | 
						|
        bonziLeft = bonziLeft + ((mouseLeft - bonziLeft) * speed);
 | 
						|
        bonzi.style.top = `${bonziTop}px`;
 | 
						|
        bonzi.style.left = `${bonziLeft}px`;
 | 
						|
        requestAnimationFrame(moveBonzi);
 | 
						|
    })();
 | 
						|
 | 
						|
    ['mousemove', 'touchstart', 'touchmove'].forEach(type => {
 | 
						|
       window.addEventListener(type, event => {
 | 
						|
           mouseTop = event.clientY || event.touches[0].clientY;
 | 
						|
           mouseLeft = event.clientX || event.touches[0].clientX;
 | 
						|
           banana.style.top = `${mouseTop}px`;
 | 
						|
           banana.style.left = `${mouseLeft}px`;
 | 
						|
       });
 | 
						|
    });
 | 
						|
 | 
						|
    //live
 | 
						|
    const live = document.getElementById('live');
 | 
						|
    const liveSrc = new URL('index.m3u8', socials.live.link).toString();
 | 
						|
 | 
						|
    const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
 | 
						|
    const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
 | 
						|
 | 
						|
    // resize video if view width is smaller than frame
 | 
						|
    if (parseInt(live.width, 10) > vw) {
 | 
						|
        live.width = `${vw}px`;
 | 
						|
        live.height = `${vw * (9 / 16)}px`;
 | 
						|
    }
 | 
						|
 | 
						|
    (function loadStream() {
 | 
						|
        // remove stream if embedded
 | 
						|
        if (window.self !== window.top) {
 | 
						|
            live.remove();
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        if (Hls.isSupported()) {
 | 
						|
            const hls = new Hls({
 | 
						|
                maxLiveSyncPlaybackRate: 1.5,
 | 
						|
            });
 | 
						|
 | 
						|
            hls.on(Hls.Events.ERROR, (event, data) => {
 | 
						|
                if (data.fatal) {
 | 
						|
                    live.style.display = 'none';
 | 
						|
                    hls.destroy();
 | 
						|
                }
 | 
						|
                setTimeout(loadStream, 5000);
 | 
						|
            });
 | 
						|
            hls.on(Hls.Events.MEDIA_ATTACHED, () => {
 | 
						|
                hls.loadSource(liveSrc);
 | 
						|
            });
 | 
						|
            hls.on(Hls.Events.MANIFEST_PARSED, () => {
 | 
						|
                live.style.removeProperty('display');
 | 
						|
                live.play();
 | 
						|
            });
 | 
						|
 | 
						|
            hls.attachMedia(live);
 | 
						|
        } else if (live.canPlayType('application/vnd.apple.mpegurl')) {
 | 
						|
            fetch(liveSrc)
 | 
						|
                .then(() => {
 | 
						|
                    live.src = liveSrc;
 | 
						|
                    live.play();
 | 
						|
                });
 | 
						|
        }
 | 
						|
    })();
 | 
						|
 | 
						|
    // animated anchors
 | 
						|
    const minSpeed = 10;
 | 
						|
    const maxSpeed = 20;
 | 
						|
    let anchors = 0;
 | 
						|
    const maxAnchors = Math.floor(vw / 30);
 | 
						|
 | 
						|
    function animateAnchor(anchor) {
 | 
						|
        let flag = parseInt(anchor.style.left, 10);
 | 
						|
 | 
						|
        setInterval(() => {
 | 
						|
            anchor.style.left = `${--flag}px`;
 | 
						|
 | 
						|
            if (anchor.offsetWidth <= -flag) {
 | 
						|
                flag = vw + Math.floor(anchor.offsetWidth / 2);
 | 
						|
                let posy = Math.floor(Math.random() * vh) - Math.floor(anchor.offsetHeight / 2);
 | 
						|
                anchor.style.top = `${posy}px`;
 | 
						|
            }
 | 
						|
        }, Math.floor(Math.random() * (maxSpeed - minSpeed) + minSpeed));
 | 
						|
    }
 | 
						|
 | 
						|
    function createAnchor(link, content) {
 | 
						|
        if (anchors >= maxAnchors) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        const anchor = document.createElement('a');
 | 
						|
        anchor.href = link;
 | 
						|
        anchor.target = '_blank';
 | 
						|
        anchor.innerHTML = content;
 | 
						|
 | 
						|
        const posTop = Math.floor(Math.random() * vh) - Math.floor(anchor.offsetHeight / 2);
 | 
						|
        const posLeft = Math.floor(Math.random() * vw) - Math.floor(anchor.offsetWidth / 2);
 | 
						|
        let zIndex = Math.floor(anchors - maxAnchors / 2);
 | 
						|
        zIndex = (zIndex >= 0) ? zIndex + 1 : zIndex;
 | 
						|
 | 
						|
        anchor.style.position = 'absolute';
 | 
						|
        anchor.style.top = `${posTop}px`;
 | 
						|
        anchor.style.left = `${posLeft}px`;
 | 
						|
        anchor.style.zIndex = `${zIndex}`;
 | 
						|
 | 
						|
        document.body.prepend(anchor);
 | 
						|
        ++anchors;
 | 
						|
        animateAnchor(anchor);
 | 
						|
    }
 | 
						|
 | 
						|
    // Always have socials
 | 
						|
    while (anchors < maxAnchors / 4) {
 | 
						|
        for (const key in socials) {
 | 
						|
            createAnchor(socials[key].link, socials[key].text);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // feed
 | 
						|
    fetch(`${socials.feed.link}.rss`)
 | 
						|
        .then(response => response.text())
 | 
						|
        .then(str => new DOMParser().parseFromString(str, 'text/xml'))
 | 
						|
        .then(data => {
 | 
						|
            const items = data.querySelectorAll('item');
 | 
						|
            items.forEach(element => {
 | 
						|
                const text = document.createElement('p');
 | 
						|
                text.innerHTML = (element.getElementsByTagName('content:encoded')[0] ?? element.getElementsByTagName('title')[0]).textContent;
 | 
						|
                createAnchor(element.querySelector('link').innerHTML, text.outerHTML);
 | 
						|
            });
 | 
						|
        });
 | 
						|
 | 
						|
    // code + helpers
 | 
						|
    function absoluteURL(data, query, url) {
 | 
						|
        data.querySelectorAll(query).forEach(element => {
 | 
						|
            element.setAttribute('href', new URL(element.getAttribute('href'), url));
 | 
						|
            element.removeAttribute('rel');
 | 
						|
        });
 | 
						|
        return data;
 | 
						|
    }
 | 
						|
 | 
						|
    function htmlDecode(input) {
 | 
						|
        let doc = new DOMParser().parseFromString(input, 'text/html');
 | 
						|
        doc = new DOMParser().parseFromString(doc.documentElement.textContent, 'text/html');
 | 
						|
        return doc;
 | 
						|
    }
 | 
						|
 | 
						|
    fetch(`${socials.code.link}.atom`)
 | 
						|
        .then(response => response.text())
 | 
						|
        .then(str => new DOMParser().parseFromString(str, 'text/xml'))
 | 
						|
        .then(data => {
 | 
						|
            data = absoluteURL(data, 'link', socials.code.link);
 | 
						|
            const items = data.querySelectorAll('entry');
 | 
						|
            items.forEach(element => {
 | 
						|
                const title = absoluteURL(htmlDecode(element.querySelector('title').innerHTML), 'a', socials.code.link);
 | 
						|
                createAnchor(element.querySelector('link').getAttribute('href'), title.body.innerHTML);
 | 
						|
            });
 | 
						|
        });
 | 
						|
</script>
 | 
						|
</body>
 | 
						|
 | 
						|
</html>
 |