SPAM RADIO
Enable audio?
you
are
the
and
I
am
a
but
be
to
in
of
me
my
your
is
we
`); return; }canvas.toBlob(function (blob) { const url = URL.createObjectURL(blob);if (navigator.share) { const file = new File([blob], 'spam-radio-poem.png', { type: 'image/png' });navigator.share({ files: [file], title: 'My Spam Radio Poem', text: 'Check out my magnetic poetry creation!' }) .then(() => showImageFeedback()) .catch(() => forceDownload(url)); } else { forceDownload(url); } }, 'image/png');} catch (e) { console.error('Mobile image save failed:', e); const image = canvas.toDataURL('image/png'); const win = window.open(); win.document.write(``); } }function forceDownload(url) { const link = document.createElement('a'); link.download = 'spam-radio-poem.png'; link.href = url; document.body.appendChild(link); link.click(); document.body.removeChild(link); setTimeout(() => { URL.revokeObjectURL(url); }, 1000); showImageFeedback(); }function saveImageForDesktop(canvas) { try { const image = canvas.toDataURL('image/png'); const link = document.createElement('a'); link.download = 'spam-radio-poem.png'; link.href = image; link.click(); showImageFeedback(); } catch (e) { alert('Error saving image. Please try again.'); } }function showImageFeedback() { const feedback = document.createElement('div'); feedback.className = 'share-feedback'; feedback.textContent = 'Image saved!'; document.body.appendChild(feedback); setTimeout(() => feedback.remove(), 2000); }/* ============================================ HELPER FUNCTIONS ============================================ */ function getRandomSubset(array, count) { const shuffled = [...array].sort(() => Math.random() - 0.5); return shuffled.slice(0, Math.min(count, array.length)); }function getClientX(e) { if (e.touches && e.touches[0]) return e.touches[0].clientX; if (e.changedTouches && e.changedTouches[0]) return e.changedTouches[0].clientX; return e.clientX; }function getClientY(e) { if (e.touches && e.touches[0]) return e.touches[0].clientY; if (e.changedTouches && e.changedTouches[0]) return e.changedTouches[0].clientY; return e.clientY; }function isMobileDevice() { return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); }function showQuickFeedback(message, type = 'info', duration = 3000) { const existing = document.querySelector('.quick-feedback'); if (existing) existing.remove(); const feedback = document.createElement('div'); feedback.className = 'quick-feedback'; feedback.textContent = message; const bgColor = { success: '#4CAF50', error: '#f44336', warning: '#ff9800', info: '#2196F3', loading: '#666' }[type] || '#2196F3'; feedback.style.cssText = ` position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background: ${bgColor}; color: white; padding: 12px 20px; border-radius: 25px; font-weight: bold; z-index: 10000; box-shadow: 0 4px 15px rgba(0,0,0,0.3); white-space: nowrap; `; document.body.appendChild(feedback); setTimeout(() => { if (feedback.parentNode) { feedback.parentNode.removeChild(feedback); } }, duration); } // Temporary debug function function debugApp() { console.log('=== DEBUG INFO ==='); console.log('currentCategoryPool:', document.getElementById('currentCategoryPool')); console.log('categoryTitle:', document.getElementById('categoryTitle')); console.log('shuffleBtn:', document.getElementById('shuffleBtn')); console.log('currentCategory:', currentCategory); console.log('displayedWords:', displayedWords); console.log('boardWords:', boardWords); }// Call this after init to check setTimeout(debugApp, 1000);/* ============================================ LOAD SHARED POEM ============================================ */ function applyLoadedMode(mode) { const poetryContainerEl = document.querySelector('.poetry-container'); const permanentTopWordsEl = document.querySelector('.permanent-top-words');if (!poetryContainerEl) return;if (mode === 'cheat') { poetryContainerEl.classList.add('cheat-active'); if (permanentTopWordsEl) permanentTopWordsEl.style.display = 'none'; } else { poetryContainerEl.classList.remove('cheat-active'); if (permanentTopWordsEl) permanentTopWordsEl.style.display = 'flex'; } }function loadSharedPoem() { const urlParams = new URLSearchParams(window.location.search); const hashParams = window.location.hash.substring(1);let poemData = null;if (urlParams.has('poem')) { poemData = urlParams.get('poem'); } else if (hashParams.includes('poem=')) { const match = hashParams.match(/poem=([^&]+)/); if (match) poemData = match[1]; }if (!poemData) return false;const decodedPoem = decodePoemFromURL(poemData); if (!decodedPoem || !decodedPoem.words) return false;// Load words boardWords = decodedPoem.words;// Restore custom words (if present) if (decodedPoem.customWords) { customWords = decodedPoem.customWords.slice(0, MAX_CUSTOM_WORDS); allCategoryWords.custom = [...customWords]; if (customCount) customCount.textContent = customWords.length; }// Restore mode (backwards compatible) // If old links don't have mode, default to normal const mode = decodedPoem.mode || 'normal';// Keep any global state you use elsewhere (optional) if (typeof lastBuiltMode !== 'undefined') { lastBuiltMode = mode; }// Apply layout state before rendering (prevents clipping) applyLoadedMode(mode);// Render renderBoardWords();// If viewing Custom tab, refresh pool if (currentCategory === 'custom') { loadCategoryWords('custom'); }// Force a paint + reflow to avoid mobile "last line clipped" issues requestAnimationFrame(() => { renderBoardWords(); if (poetryBoard) void poetryBoard.offsetHeight; });return true; }function decodePoemFromURL(encoded) { if (!encoded) return null;try { let padded = encoded; while (padded.length % 4) padded += '='; padded = padded.replace(/-/g, '+').replace(/_/g, '/');const binary = atob(padded); const bytes = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); }const decoder = new TextDecoder(); const jsonString = decoder.decode(bytes); const compressedData = JSON.parse(jsonString);if (!compressedData.w || !Array.isArray(compressedData.w)) { return null; }const words = compressedData.w.map((wordData, index) => ({ id: Date.now() + Math.random() + index, text: wordData.t, x: Number(wordData.x) || 50 + (index % 5) * 60, y: Number(wordData.y) || 50 + Math.floor(index / 5) * 40, zIndex: index, isIcon: Boolean(wordData.i) }));return { words, customWords: Array.isArray(compressedData.c) ? compressedData.c : [], mode: compressedData.m || 'normal', // ✅ NEW: 'cheat' or 'normal' (old links default) timestamp: compressedData.ts || Date.now() }; } catch (error) { console.error('Error decoding poem:', error); return null; } }// Wait for DOM to be fully loaded if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { console.log('DOM fully loaded, initializing poetry app...'); init(); }); } else { // DOM is already ready console.log('DOM already ready, initializing poetry app...'); init(); }document.getElementById('musicToggleBtn')?.addEventListener('click', () => { window.dispatchEvent(new Event('sr:open')); });

SUBMIT A TERM

This form records words that point to lived distinctions not yet clearly named.

Submissions are reviewed, edited, or quietly archived. Not all terms will be published.

Departmental Linguistics intake
Public access. Curated archive.

Why share your prayers and intentions?

Well, we tend to get back what we give out. Hopefully you have been inspired by some of the shares, so maybe pay it forward and inspire others on what hopes to be the largest living Prayer intentions and gratitude wall in the universe.

Lets turn good intentions into new realities and spread the good that we all long for….

Free Tee Podcast Application

Tell Us Why one of the Designs Speaks to You – Get your voice heard and the Tee for Free if we publish the podcast!

Apply to be featured on the QR Poet podcast.
Share your take on one of our designs. If selected, you’ll get the T-shirt for free when we record a short podcast conversation exploring your meaning behind the message.

🎙️ 12 spots only. One per design.
💬 Reflect. Record. Receive.

Based in the Derbyshire Uk we not only design make inspiring designs but also champion and well being projects and run the Qrious Threads podcast. If you have an order query or would like to get involved with what we do then please get in touch.

Tell Us Why one of our Designs Speak to You – Get your voice heard and the Tee for Free if we publish the podcast!

Apply to be featured on the QR Threads podcast.

Share your reflections sparked by one of our designs. If selected, you’ll get the T-shirt for free when we record a short podcast conversation exploring your meaning behind the message.

🎙️ 3 spots per month. One per design.
💬 Reflect. Record. Receive.

Free T-shirt will be sent if podcast is aired. You have full consent if finished podcast is broadcast.

The Department would love to hear from you

Please get in touch if you would like to know more.