import QRCode from 'qrcode';
import './style.css';
const initial = 'https://huggingface.co/datasets/evalstate/mcp-clients';
const themes = [
{id:'phosphor',name:'Green phosphor',code:'P1',accent:'#a7f878',ink:'#123822',paper:'#edfadf',description:'Late nights. Green screens. Pure signal.'},
{id:'amber',name:'Amber console',code:'P2',accent:'#ffbd69',ink:'#492b0d',paper:'#fff0d4',description:'A warm glow from a different era.'},
{id:'ice',name:'Arctic terminal',code:'P3',accent:'#91d9ff',ink:'#12304a',paper:'#e9f6ff',description:'Cold pixels. A very clear connection.'}
];
let current=themes[0], svg='', revision=0;
let logoData='';
const logo = new Image();
const response = await fetch('/hf-logo-pirate.png');
const blob = await response.blob();
logoData = await new Promise(resolve=>{const reader=new FileReader();reader.onload=()=>resolve(reader.result);reader.readAsDataURL(blob)});
logo.src=logoData; await logo.decode();
document.querySelector('#app').innerHTML=`
▥ SIGNAL/QR STUDIO LOCAL ENCODING · NO TRACKING
UTILITY_001 / LINKS → PIXELS
Your link. A little more signal.
QR codes with an old-school soul. Pick a frequency, drop in a link, and send it out into the world.
01 / INPUTHTTP(S)
›
Static by design. Your URL, directly encoded.
02 / FREQUENCY
${themes.map((t,i)=>``).join('')}
Hugging Face logo, front and center.
Larger logos cover more data. Test with your phone before printing.
Shown in the preview and both downloads.
↳
Built for the real world. High error correction. A clean quiet zone. No redirects, accounts, or expiration.
LIVE PREVIEWP1 / PHOSPHOR
HF / TRANSMISSION
${current.description}ECC / H
● SIGNAL READY
Take your pixels with you.
`;
const input=document.querySelector('#url');
function validURL(value){try {const u=new URL(value);return ['http:','https:'].includes(u.protocol)&&!!u.hostname;}catch{return false}}
function update(){
revision++;
const includeHeader=document.querySelector("#include-header").checked;
document.querySelector(".card-top").hidden=!includeHeader;
document.querySelector("#header-preview").textContent=document.querySelector("#header-text").value;
document.querySelector("#header-text").disabled=!includeHeader;
document.querySelector("#size-value").textContent=document.querySelector("#logo-size").value+"%";
document.querySelector("#logo-size").disabled=!document.querySelector("#logo").checked;
const value=input.value.trim();
const valid=validURL(value);
document.querySelector('#error').textContent=valid?'Static by design. Your URL, directly encoded.':'Enter a complete URL starting with https:// or http://.';
input.setAttribute('aria-invalid',String(!valid));
document.querySelectorAll('.actions button').forEach(b=>b.disabled=!valid);
if(!valid){svg='';document.querySelector('#qr').innerHTML='
AWAITING VALID URL
';document.querySelector('#status').textContent='○ AWAITING INPUT';return}
try {
const qr=QRCode.create(value,{errorCorrectionLevel:'H'});const n=qr.modules.size, size=n+8;
// A modest centered logo; all finder/timing patterns and the 4-module quiet zone remain intact.
const logoSize=Math.floor(n*Number(document.querySelector("#logo-size").value)/100),start=(size-logoSize)/2;
let path='';for(let y=0;y${withLogo?``:''}`;
document.querySelector('#qr').innerHTML=svg;document.querySelector('#status').textContent='● SIGNAL READY';
}catch{svg='';document.querySelector('#qr').innerHTML='
URL TOO LONG
';document.querySelector('#error').textContent='This URL exceeds QR capacity. Try a shorter URL.';document.querySelector('#status').textContent='○ INPUT TOO LONG';document.querySelectorAll('.actions button').forEach(b=>b.disabled=true)}
}
function save(blob,ext){const a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=`signal-${current.id}.${ext}`;a.click();setTimeout(()=>URL.revokeObjectURL(a.href),1000)}
function exportSVG(){
if(!document.querySelector('#include-header').checked)return svg;
const text=document.querySelector('#header-text').value.replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
const nested=svg.replace('width="1024" height="1024"','x="0" y="112" width="1024" height="1024"');
return ``;
}
document.querySelector('#svg').onclick=()=>{if(svg)save(new Blob([exportSVG()],{type:'image/svg+xml'}),'svg')};
document.querySelector('#png').onclick=async()=>{if(!svg)return;const version=revision;const image=new Image();image.src=URL.createObjectURL(new Blob([exportSVG()],{type:'image/svg+xml'}));try{await image.decode();if(version!==revision)return;const canvas=document.createElement('canvas');canvas.width=1024;canvas.height=image.naturalHeight;canvas.getContext('2d').drawImage(image,0,0);canvas.toBlob(blob=>{if(blob)save(blob,'png')},'image/png')}finally{URL.revokeObjectURL(image.src)}};
for(const id of ['logo-size','include-header','header-text'])document.getElementById(id).addEventListener('input',update);
input.addEventListener('input',update);document.querySelector('#logo').onchange=update;
document.querySelectorAll('.theme').forEach(button=>button.onclick=()=>{current=themes.find(t=>t.id===button.dataset.theme);document.documentElement.style.setProperty('--accent',current.accent);document.documentElement.style.setProperty('--paper',current.paper);document.documentElement.style.setProperty('--ink',current.ink);document.querySelectorAll('.theme').forEach(b=>{b.classList.toggle('selected',b===button);b.setAttribute('aria-pressed',String(b===button))});document.querySelector('#preview-code').textContent=`${current.code} / ${current.id.toUpperCase()}`;document.querySelector('#description').textContent=current.description;update()});update();