<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>One Day Projects &#8211; interloper.</title>
	<atom:link href="https://interloper.ie/category/one-day-projects/feed/" rel="self" type="application/rss+xml" />
	<link>https://interloper.ie</link>
	<description>Marcus Craig - Artist &#38; Technician</description>
	<lastBuildDate>Wed, 03 Jun 2026 12:55:34 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://interloper.ie/wp-content/uploads/2023/10/Untitled-2-150x150.webp</url>
	<title>One Day Projects &#8211; interloper.</title>
	<link>https://interloper.ie</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>QR Code Anything &#8211; Infinite* data encode/decode</title>
		<link>https://interloper.ie/qr-code/</link>
		
		<dc:creator><![CDATA[root]]></dc:creator>
		<pubDate>Sun, 10 May 2026 11:49:53 +0000</pubDate>
				<category><![CDATA[One Day Projects]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[encoding]]></category>
		<category><![CDATA[qr code]]></category>
		<guid isPermaLink="false">https://interloper.ie/?p=1112</guid>

					<description><![CDATA[]]></description>
										<content:encoded><![CDATA[
<style>
/* ===== Page chrome (post 1112 only) ===== */
body.postid-1112 {
  background: #062324 !important;
  color: #F0D0B1;
}
body.postid-1112 a { color: #F0D0B1; text-decoration: none; }
body.postid-1112 a:hover { color: #F0D0B1; opacity: 0.75; }

body.postid-1112 .wp-block-site-title,
body.postid-1112 .wp-block-site-title a { color: #F0D0B1 !important; }

body.postid-1112 .wp-block-navigation,
body.postid-1112 .wp-block-navigation-item,
body.postid-1112 .wp-block-navigation-item__content,
body.postid-1112 .wp-block-navigation-item__label,
body.postid-1112 .wp-block-navigation a { color: #F0D0B1 !important; }

body.postid-1112 .wp-block-post-terms,
body.postid-1112 .wp-block-post-terms a,
body.postid-1112 .wp-block-post-terms__separator { color: #F0D0B1 !important; }
body.postid-1112 .taxonomy-post_tag,
body.postid-1112 .taxonomy-post_tag a { color: rgba(240, 208, 177, 0.7) !important; }

body.postid-1112 h1,
body.postid-1112 h2,
body.postid-1112 h3,
body.postid-1112 h4 { color: #F0D0B1; }

body.postid-1112 .search-icon,
body.postid-1112 img[src*="Magnifying_glass"] {
  filter: invert(88%) sepia(20%) saturate(450%) hue-rotate(330deg) brightness(95%);
}

/* Hide the QR iframe until we've injected its dark palette, to avoid a flash of the original light theme. */
body.postid-1112 iframe[src*="qr_project_finished"] { visibility: hidden; }
body.postid-1112 iframe[src*="qr_project_finished"].qr-themed { visibility: visible; }
</style>
<script>
(function () {
  // CSS injected into the QR iframe's own document (same-origin, so this is allowed).
  // Keeps the project file itself untouched — all theming lives in this post.
  var iframeCSS = [
    ':root {',
    '  --color-bg: #062324;',
    '  --color-accent: #F0D0B1;',
    '  --color-border-primary: rgba(240, 208, 177, 0.75);',
    '  --color-border-secondary: rgba(240, 208, 177, 0.55);',
    '  --color-border-tertiary: rgba(240, 208, 177, 0.35);',
    '  --color-text-primary: #F0D0B1;',
    '  --color-text-secondary: rgba(240, 208, 177, 0.7);',
    '  --color-text-danger: #ff8a7a;',
    '  --color-background-secondary: transparent;',
    '  --color-background-tertiary: rgba(240, 208, 177, 0.12);',
    '}',
    'body { background: #062324 !important; color: #F0D0B1; }',
    'textarea.ta {',
    '  background: rgba(240, 208, 177, 0.06);',
    '  color: #F0D0B1;',
    '  caret-color: #F0D0B1;',
    '}',
    'textarea.ta::placeholder { color: rgba(240, 208, 177, 0.45); }',
    'textarea.ta:focus { outline: none; border-color: rgba(240, 208, 177, 0.75); }',
    '.btn { transition: background 0.15s ease, border-color 0.15s ease; }',
    '.btn:hover { border-color: rgba(240, 208, 177, 0.75); }',
    'input[type="checkbox"] { accent-color: #F0D0B1; }',
    '.qr span { color: #666666 !important; }',
    '.qr span[style*="danger"] { color: #cc2222 !important; }'
  ].join('\n');

  function injectInto(iframe) {
    try {
      var doc = iframe.contentDocument;
      if (!doc || !doc.head) return false;
      if (doc.getElementById('qr-post-theme')) {
        iframe.classList.add('qr-themed');
        return true;
      }
      var style = doc.createElement('style');
      style.id = 'qr-post-theme';
      style.textContent = iframeCSS;
      doc.head.appendChild(style);
      iframe.classList.add('qr-themed');
      return true;
    } catch (e) {
      return false;
    }
  }

  function attach(iframe) {
    if (iframe.dataset.qrThemeBound) return;
    iframe.dataset.qrThemeBound = '1';
    // Try immediately (cached / already-loaded case).
    injectInto(iframe);
    iframe.addEventListener('load', function () { injectInto(iframe); });
    // Safety: also poll briefly in case head appears before load fires.
    var tries = 0;
    var poll = setInterval(function () {
      if (injectInto(iframe) || ++tries > 40) clearInterval(poll);
    }, 50);
  }

  function scan() {
    var iframes = document.querySelectorAll('iframe[src*="qr_project_finished"]');
    for (var i = 0; i < iframes.length; i++) attach(iframes[i]);
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', scan);
  } else {
    scan();
  }
})();
</script>


<iframe id="render-html-1" src="https://interloper.ie/wp-content/uploads/qr_project_finished.html" scrolling="no" frameborder="0" style="border:none;display:block;width:100%;overflow:hidden;" title="Embedded HTML"></iframe>
<script>(function(){var f=document.getElementById("render-html-1");function r(){try{f.style.height=f.contentDocument.documentElement.scrollHeight+"px";}catch(e){}}f.addEventListener("load",function(){r();try{new MutationObserver(r).observe(f.contentDocument.body,{childList:true,subtree:true,attributes:true,characterData:true});}catch(e){}});}());</script>

]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Terminal</title>
		<link>https://interloper.ie/terminal/</link>
		
		<dc:creator><![CDATA[root]]></dc:creator>
		<pubDate>Sat, 09 Aug 2025 19:02:00 +0000</pubDate>
				<category><![CDATA[One Day Projects]]></category>
		<category><![CDATA[cli]]></category>
		<category><![CDATA[one-day-project]]></category>
		<category><![CDATA[operating system]]></category>
		<category><![CDATA[os]]></category>
		<category><![CDATA[terminal]]></category>
		<guid isPermaLink="false">https://www.interloper.ie/?p=702</guid>

					<description><![CDATA[Terminal OS It has been a while since I made a one-day project. Always enjoyed the idea of a web based &#8216;terminal&#8217; that mimics a SSH connection or a headless CLI. I could easily expose a MySQL demo user and designate a sandbox portion of my VM &#8211; but making it a single HTML is [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 data-wp-context---core-fit-text="core/fit-text::{&quot;fontSize&quot;:&quot;&quot;}" data-wp-init---core-fit-text="core/fit-text::callbacks.init" data-wp-interactive data-wp-style--font-size="core/fit-text::context.fontSize" class="wp-block-heading has-fit-text">Terminal OS</h2>


<div class="wp-block-post-date"><time datetime="2025-08-09T21:02:00+02:00">09/08/2025</time></div>


<p class="wp-block-paragraph">It has been a while since I made a one-day project. Always enjoyed the idea of a web based &#8216;terminal&#8217; that mimics a SSH connection or a headless CLI. I could easily expose a MySQL demo user and designate a sandbox portion of my VM &#8211; but making it a single HTML is much more fun (and, you know, safe).<br><br>Adding a few functions that pull from some public APIs such as a weather search and some selected news headlines via RSS. Adding the ability to query the WordPress CMS so you can search Pages/Posts, all without requiring its REST API. I could always add some persistence with some PHP sessions or even just the browsers localStorage, but I prefer this to be as instanced and lightweight as possible. This is all contained within a single HTML file (&lt;20kb).<br><br>This project can be found formerly at <a href="https://interloper.ie/os">interloper.ie/os</a></p>



<!-- Terminal iframe wrapper -->
<style>
.terminal-embed{
  position:relative;
  width:100%;
  aspect-ratio:16/9;                 /* default desktop letterbox */
  overflow:hidden;
  border-radius:16px;
  box-shadow:0 2px 16px rgba(0,0,0,.08);
  background:#0b0b0b;
}

/* The iframe */
.terminal-embed iframe{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  border:0;
}

/* Fullscreen button */
.terminal-embed .fs-btn{
  position:absolute;
  top:10px;
  right:10px;
  z-index:2;                         /* ensure above iframe */
  display:inline-flex;
  align-items:center;
  gap:.45rem;
  padding:.5rem .7rem;
  border-radius:10px;
  background:rgba(10,10,10,.7);
  color:#e8e8e8;
  border:1px solid rgba(255,255,255,.15);
  backdrop-filter: blur(4px);
  cursor:pointer;
  font:500 13px/1 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
  user-select:none;

  opacity:0;
  transform: translateY(-4px);
  transition: opacity .18s ease, transform .18s ease, background .18s ease;
}
.terminal-embed .fs-btn:hover{ background:rgba(10,10,10,.85); }
.terminal-embed .fs-btn svg{ width:16px; height:16px; }

/* Fade in on hover/focus, and keep shown while fullscreen */
.terminal-embed:hover .fs-btn,
.terminal-embed:focus-within .fs-btn,
.terminal-embed.is-fullscreen .fs-btn{
  opacity:1;
  transform:none;
}

/* No hover (touch): keep visible */
@media (hover:none){
  .terminal-embed .fs-btn{ opacity:1; transform:none; }
}

/* Phones in portrait: use viewport height instead of 16:9 */
@media (max-width:700px) and (orientation:portrait){
  .terminal-embed{ aspect-ratio:auto; height:85vh; }
  .terminal-embed iframe{ height:100%; }
}
</style>

<div class="terminal-embed" id="terminal-embed" aria-label="Interactive terminal embed">
  <button class="fs-btn" type="button" aria-label="Enter fullscreen" title="Fullscreen">
    <!-- “enter fullscreen” icon -->
    <svg viewBox="0 0 24 24" aria-hidden="true">
      <path fill="currentColor"
        d="M7 3h2v4h4v2H7V3zm8 0h2v6h-6V7h4V3zM7 13h6v4H9v4H7v-8zm10 0v8h-2v-4h-4v-2h6z"/>
    </svg>
    <span class="fs-text">Fullscreen</span>
  </button>

  <iframe
    id="terminal-frame"
    src="/wp-content/uploads/2025/08/terminal2.html"
    title="terminal"
    loading="lazy"
    allow="fullscreen"
    allowfullscreen
  ></iframe>
</div>

<script>
(function(){
  const wrap   = document.getElementById('terminal-embed');
  const btn    = wrap.querySelector('.fs-btn');
  const label  = btn.querySelector('.fs-text');
  const svg    = btn.querySelector('svg');
  const iframe = document.getElementById('terminal-frame');

  function isFS(){
    return document.fullscreenElement === wrap
        || document.webkitFullscreenElement === wrap;
  }

  async function enterFS(){
    try{
      if (wrap.requestFullscreen) await wrap.requestFullscreen();
      else if (wrap.webkitRequestFullscreen) wrap.webkitRequestFullscreen(); // Safari
    }catch(e){ console.warn('Fullscreen request failed:', e); }
  }

  function exitFS(){
    if (document.exitFullscreen) document.exitFullscreen();
    else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
  }

  function toggleFS(){
    if (isFS()) exitFS();
    else enterFS();
  }

  // Try to focus the terminal inside the iframe
  function focusTerminalInIframe(){
    try {
      // direct same-origin call
      iframe.contentWindow?.focusTerminal?.();
    } catch(e) {
      // Cross-origin safety; shouldn't happen for same-site
      console.warn('Could not call focusTerminal on iframe:', e);
    }
  }

  function updateUI(){
    const active = isFS();
    wrap.classList.toggle('is-fullscreen', active);
    btn.setAttribute('aria-label', active ? 'Exit fullscreen' : 'Enter fullscreen');
    btn.title = active ? 'Exit fullscreen' : 'Fullscreen';
    label.textContent = active ? 'Exit' : 'Fullscreen';
    svg.style.transform = active ? 'rotate(180deg)' : 'none';

    // When entering fullscreen, nudge focus a few times to beat timing quirks
    if (active) {
      focusTerminalInIframe();
      setTimeout(focusTerminalInIframe, 50);
      setTimeout(focusTerminalInIframe, 150);
    }
  }

  btn.addEventListener('click', () => {
    toggleFS();
    // Also try immediately on click (helps on some browsers)
    setTimeout(focusTerminalInIframe, 0);
  });

  document.addEventListener('fullscreenchange', updateUI);
  document.addEventListener('webkitfullscreenchange', updateUI);
  updateUI();
})();
</script>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
