<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Code on Strings And Tines</title><link>http://stringsandtines.com/code/</link><description>Recent content in Code on Strings And Tines</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>© 2026</copyright><lastBuildDate>Sun, 12 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="http://stringsandtines.com/code/index.xml" rel="self" type="application/rss+xml"/><item><title>Volleyball Stats Tracker</title><link>http://stringsandtines.com/code/volleyballstatstracker/</link><pubDate>Sun, 12 Apr 2026 00:00:00 +0000</pubDate><guid>http://stringsandtines.com/code/volleyballstatstracker/</guid><description>&lt;style>
.vb-app-box {
max-width: 550px;
margin: 0 auto;
background-color: #121212;
color: #ffffff;
font-family: sans-serif;
border-radius: 8px;
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
overflow: hidden;
}
.vb-app-header {
position: sticky;
top: 0;
background: #1e1e1e;
padding: 12px 15px;
z-index: 50;
border-bottom: 2px solid #3498db;
display: flex;
justify-content: space-between;
align-items: center;
}
.vb-app-header h2 { margin: 0 !important; font-size: 1.1rem !important; color: #3498db !important; border: none !important; }
.vb-app-set-pill { font-weight: bold; background: #3498db; padding: 4px 10px; border-radius: 4px; color: white; }
.vb-app-body { padding: 15px; }
.vb-app-input-group {
background: #1e1e1e;
padding: 10px;
border-radius: 6px;
margin-bottom: 15px;
}
.vb-app-body input {
width: 100%;
padding: 12px;
margin: 4px 0 8px 0;
background: #2c2c2c;
border: 1px solid #444;
color: white;
border-radius: 4px;
box-sizing: border-box;
font-size: 16px;
}
.vb-app-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 20px;
}
.vb-app-stat-card {
background: #2c2c2c;
padding: 12px;
border-radius: 6px;
text-align: center;
border-left: 4px solid #95a5a6;
}
.vb-app-stat-card.vb-hl { border-left-color: #27ae60; }
.vb-app-stat-card.vb-std { border-left-color: #3498db; }
.vb-app-label { font-size: 0.7rem; text-transform: uppercase; color: #bbb; display: block; margin-bottom: 4px; }
.vb-app-val { font-size: 1.8rem; font-weight: bold; margin: 4px 0; color: #fff; }
.vb-app-btns { display: flex; gap: 8px; }

/* Perfect centering for + and - */
.vb-app-box button {
flex: 1;
height: 55px; /* Fixed height for consistent hit area */
border: none;
border-radius: 4px;
font-weight: bold;
color: white;
font-size: 1.8rem;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
line-height: 0;
padding: 0;
}

.vb-app-plus { background-color: #27ae60; }
.vb-app-minus { background-color: #e74c3c; opacity: 0.7; }

/* Wide utility buttons */
.vb-app-wide { 
width: 100%; 
margin-top: 10px; 
height: 60px !important; 
font-size: 1.1rem !important; 
}
.vb-app-next { background-color: #3498db; }
.vb-app-reset { background-color: #444; }
.vb-app-danger { background-color: transparent; border: 1px solid #e74c3c; color: #e74c3c; margin-top: 30px; margin-bottom: 40px; }
&lt;/style>
&lt;div class="vb-app-box">
&lt;div class="vb-app-header">
&lt;div>
&lt;h2 id="v-disp-n">Player Name&lt;/h2>
&lt;span id="v-disp-t" style="font-size: 0.8rem; color: #aaa;">Team vs Opponent&lt;/span>
&lt;/div>
&lt;div class="vb-app-set-pill">SET &lt;span id="v-disp-s">1&lt;/span>&lt;/div>
&lt;/div>
&lt;div class="vb-app-body">
&lt;div class="vb-app-input-group">
&lt;input type="text" id="v-in-n" placeholder="Player Name" oninput="window.vbS()">
&lt;input type="text" id="v-in-t" placeholder="Player Team" oninput="window.vbS()">
&lt;input type="text" id="v-in-o" placeholder="Opponent" oninput="window.vbS()">
&lt;div style="display: flex; gap: 8px;">
&lt;input type="date" id="v-in-d" onchange="window.vbS()">
&lt;input type="text" id="v-in-v" placeholder="Venue" oninput="window.vbS()">
&lt;/div>
&lt;/div>
&lt;div class="vb-app-grid" id="vb-grid-target">&lt;/div>
&lt;button class="vb-app-wide vb-app-next" onclick="window.vbNext()">Next Set (Clear Stats)&lt;/button>
&lt;button class="vb-app-wide vb-app-reset" onclick="window.vbResS()">Reset Set&lt;/button>
&lt;button class="vb-app-wide vb-app-danger" onclick="window.vbFull()">Full Reset Page&lt;/button>
&lt;/div>
&lt;/div>
&lt;script>
(function() {
let stats = { blocks: 0, ace: 0, freeball: 0, dump: 0, kill: 0, serve: 0, push: 0, points: 0 };
let set = 1;
const labels = { blocks: "Blocks", ace: "Ace", freeball: "Free Ball", dump: "Dump", kill: "Kill", serve: "Serve", push: "Push", points: "Points Scored" };

window.vbS = function() {
const nEl = document.getElementById('v-in-n');
const tEl = document.getElementById('v-in-t');
const oEl = document.getElementById('v-in-o');
const dEl = document.getElementById('v-in-d');
const vEl = document.getElementById('v-in-v');
if(nEl) document.getElementById('v-disp-n').innerText = nEl.value || "Player Name";
if(tEl &amp;&amp; oEl) document.getElementById('v-disp-t').innerText = (tEl.value || 'Team') + ' vs ' + (oEl.value || 'Opp');
document.getElementById('v-disp-s').innerText = set;
localStorage.setItem('vb_final_v6', JSON.stringify({
stats, set, meta: {
n: nEl ? nEl.value : "",
t: tEl ? tEl.value : "",
o: oEl ? oEl.value : "",
d: dEl ? dEl.value : "",
v: vEl ? vEl.value : ""
}
}));
};

window.vbR = function() {
const g = document.getElementById('vb-grid-target');
if(!g) return;
g.innerHTML = '';
for (const [k, v] of Object.entries(stats)) {
const isP = (k === 'ace' || k === 'kill' || k === 'points');
const d = document.createElement('div');
d.className = 'vb-app-stat-card ' + (isP ? 'vb-hl' : 'vb-std');
d.innerHTML = '&lt;span class="vb-app-label">' + labels[k] + '&lt;/span>&lt;div class="vb-app-val">' + v + '&lt;/div>' +
'&lt;div class="vb-app-btns">' +
'&lt;button class="vb-app-minus" onclick="window.vbC(\'' + k + '\', -1)">&lt;span>−&lt;/span>&lt;/button>' +
'&lt;button class="vb-app-plus" onclick="window.vbC(\'' + k + '\', 1)">&lt;span>+&lt;/span>&lt;/button>' +
'&lt;/div>';
g.appendChild(d);
}
};

window.vbC = function(k, a) {
stats[k] = Math.max(0, stats[k] + a);
if (a > 0 &amp;&amp; (k === 'ace' || k === 'kill')) stats.points++;
window.vbS(); window.vbR();
};

window.vbNext = function() {
if (set &lt; 3) { set++; for (let k in stats) stats[k] = 0; window.vbS(); window.vbR(); window.scrollTo(0,0); }
};

window.vbResS = function() {
if(confirm("Reset current set?")) { for (let k in stats) stats[k] = 0; window.vbS(); window.vbR(); }
};

window.vbFull = function() {
if(confirm("Full Reset? This wipes EVERYTHING.")) {
localStorage.removeItem('vb_final_v6');
const ids = ['v-in-n', 'v-in-t', 'v-in-o', 'v-in-d', 'v-in-v'];
ids.forEach(id => { const el = document.getElementById(id); if(el) el.value = ""; });
set = 1;
for (let k in stats) stats[k] = 0;
window.vbS(); 
location.reload();
}
};

const stored = localStorage.getItem('vb_final_v6');
if (stored) {
const d = JSON.parse(stored);
stats = d.stats; set = d.set;
if(document.getElementById('v-in-n')) document.getElementById('v-in-n').value = d.meta.n || "";
if(document.getElementById('v-in-t')) document.getElementById('v-in-t').value = d.meta.t || "";
if(document.getElementById('v-in-o')) document.getElementById('v-in-o').value = d.meta.o || "";
if(document.getElementById('v-in-d')) document.getElementById('v-in-d').value = d.meta.d || "";
if(document.getElementById('v-in-v')) document.getElementById('v-in-v').value = d.meta.v || "";
}
window.vbR(); window.vbS();
})();
&lt;/script></description><media:content xmlns:media="http://search.yahoo.com/mrss/" url="http://stringsandtines.com/code/volleyballstatstracker/featured.png"/></item><item><title>Weather Hologram</title><link>http://stringsandtines.com/code/weatherhologram/</link><pubDate>Sun, 27 Jul 2025 00:00:00 +0000</pubDate><guid>http://stringsandtines.com/code/weatherhologram/</guid><description>&lt;style>
 html, body {
 margin: 0;
 padding: 0;
 background: black;
 width: 100%;
 min-height: 100vh;
 overflow-y: auto;
 font-family: 'Roboto', sans-serif;
 }

 /* Wrap everything to mirror */
 #mirrorWrapper {
 -webkit-transform: scaleX(-1);
 -moz-transform: scaleX(-1);
 -ms-transform: scaleX(-1);
 -o-transform: scaleX(-1);
 transform: scaleX(-1);
 }

 #container {
 text-align: center;
 padding-top: 20px;
 }

 #weatherImg {
 transform: scale(1.5);
 transform-origin: center;
 max-width: 100%;
 height: auto;
 }

 #spacer {
 height: 150px;
 }

 #tempDisplay {
 position: absolute;
 top: 20px;
 right: 20px;
 color: white;
 font-size: 40px;
 font-weight: 100;
 z-index: 999;
 pointer-events: none;
 }
 &lt;/style>
&lt;div id="mirrorWrapper">
 &lt;div id="tempDisplay">--°C&lt;/div>
 &lt;div id="container">
 &lt;img id="weatherImg" src="sun.gif" alt="Ambient Weather Display">
 &lt;/div>
 &lt;div id="spacer">&lt;/div>
&lt;/div>
&lt;script>
 var gifs = {
 "Clear": "sun.gif",
 "Clouds": "clouds.gif",
 "Rain": "rain.gif",
 "Drizzle": "rain.gif",
 "Mist": "haze.gif",
 "Smoke": "haze.gif",
 "Haze": "haze.gif",
 "Fog": "haze.gif",
 "Thunderstorm": "thunderstorm.gif",
 "Default": "sun.gif"
 };

 var apiKey = "0279ec960d72c1817406752c091587fd";
/* var apiKey = "0b6dae9987379e1deaf001865ec26a64"; */
 var lat = "43.30";
 var lon = "-77.92";
 var apiUrl = "https://api.openweathermap.org/data/2.5/weather?lat=" + lat + "&amp;lon=" + lon + "&amp;units=imperial&amp;appid=" + apiKey;

 function updateImage(condition) {
 var gifSrc = gifs[condition] || gifs["Default"];
 document.getElementById("weatherImg").src = gifSrc;
 }

 function updateTempDisplay(temp) {
 var display = document.getElementById("tempDisplay");
 display.textContent = Math.round(temp) + "°F";
 }

 function fetchWeather() {
 var xhr = new XMLHttpRequest();
 xhr.open("GET", apiUrl, true);
 xhr.onreadystatechange = function() {
 if (xhr.readyState === 4 &amp;&amp; xhr.status === 200) {
 try {
 var data = JSON.parse(xhr.responseText);
 if (data &amp;&amp; data.weather &amp;&amp; data.weather.length > 0) {
 var condition = data.weather[0].main;
 var temp = data.main.temp;
 updateImage(condition);
 updateTempDisplay(temp);
 }
 } catch (e) {
 console.error("Error parsing JSON response:", e);
 }
 }
 };
 xhr.send();
 }

 fetchWeather();
 setInterval(fetchWeather, 600000);
&lt;/script>
&lt;div style="text-align: center;">
 &lt;div style="width: 500px; margin: 0 auto; background: #000; color: #fff;">Inspiration and code from &lt;a href="https://www.instructables.com/Trap-the-Current-Weather-in-a-Box/">here&lt;/a>. Pics of the project coming soon!&lt;/div>
&lt;/div></description><media:content xmlns:media="http://search.yahoo.com/mrss/" url="http://stringsandtines.com/code/weatherhologram/featured.webp"/></item><item><title>Cornhole Score Tracker</title><link>http://stringsandtines.com/code/cornhole/</link><pubDate>Fri, 04 Jul 2025 00:00:00 +0000</pubDate><guid>http://stringsandtines.com/code/cornhole/</guid><description>&lt;style>
/* Remove global html/body overrides to preserve theme layout */
.cornhole-container {
 width: 100vw;
 margin-left: calc(-50vw + 50%);
 font-family: sans-serif;
 min-height: 100vh;
 display: flex;
 flex-direction: column;
 justify-content: space-between;
}

/* Mobile-specific full-width override */
@media (max-width: 640px) {
 .cornhole-container {
 width: 100vw;
 margin-left: -24px; /* px-6 = 24px */
 }
}

/* Small screens and up */
@media (min-width: 641px) and (max-width: 768px) {
 .cornhole-container {
 width: 100vw;
 margin-left: -56px; /* sm:px-14 = 56px */
 }
}

/* Medium screens and up */
@media (min-width: 769px) and (max-width: 1024px) {
 .cornhole-container {
 width: 100vw;
 margin-left: -96px; /* md:px-24 = 96px */
 }
}

/* Large screens and up */
@media (min-width: 1025px) {
 .cornhole-container {
 width: 100vw;
 margin-left: -128px; /* lg:px-32 = 128px */
 }
}
.cornhole-section {
 flex: 1 1 0;
 display: flex;
 flex-direction: column;
 align-items: center;
 padding: 32px 8px 24px 8px;
 justify-content: center;
 position: relative;
}
.cornhole-section.team1 {
 background: #e53935;
 color: #fff;
 border-top-left-radius: 16px;
 border-top-right-radius: 16px;
 padding-top: 16px;
}
.cornhole-section.team2 {
 background: #1e88e5;
 color: #fff;
 border-bottom-left-radius: 16px;
 border-bottom-right-radius: 16px;
 padding-top: 40px;
 padding-bottom: 24px;
}
.cornhole-title {
 font-size: 1.5em;
 font-weight: bold;
 margin-bottom: 16px;
}
.cornhole-btn-row {
 display: flex;
 gap: 12px;
 margin-bottom: 8px;
}
.cornhole-reset-row {
 display: flex;
 justify-content: center;
 margin-bottom: 16px;
}
.cornhole-btn {
 font-size: 1.2em;
 padding: 10px 18px;
 border: none;
 border-radius: 24px;
 background: #222;
 color: #fff !important;
 font-weight: bold;
 cursor: pointer;
 box-shadow: 0 2px 6px rgba(0,0,0,0.08);
 transition: background 0.2s;
}
.cornhole-btn:active {
 background: #333;
}
.cornhole-reset-btn {
 margin-left: 0;
}
.cornhole-score-row {
 display: flex;
 flex-direction: row;
 gap: 32px;
 margin-bottom: 8px;
 width: 100%;
 max-width: 500px;
 justify-content: center;
}
.cornhole-score-col {
 display: flex;
 flex-direction: column;
 align-items: center;
 flex: 1 1 0;
}
.cornhole-label {
 font-size: 1em;
 margin-bottom: 2px;
}
.cornhole-score-box {
 width: 120px;
 font-size: 1.3em;
 text-align: center;
 padding: 8px 0;
 border-radius: 6px;
 background: #fff;
 color: #222;
 border: none;
 margin-bottom: 4px;
 pointer-events: none;
}
.cornhole-divider {
 width: 100%;
 height: 2px;
 background: #eee;
 position: relative;
 z-index: 1;
}
.cornhole-end-round-btn {
 position: absolute;
 left: 50%;
 top: 100%;
 transform: translate(-50%, -50%);
 z-index: 2;
 font-size: 1.1em;
 padding: 12px 28px;
 border-radius: 24px;
 background: #222;
 color: #fff;
 border: none;
 font-weight: bold;
 box-shadow: 0 2px 8px rgba(0,0,0,0.12);
 cursor: pointer;
 min-width: 140px;
 white-space: nowrap;
}
.cornhole-restart-btn {
 margin: 32px auto 0 auto;
 display: block;
 font-size: 1.1em;
 padding: 14px 32px;
 border-radius: 24px;
 background: #222;
 color: #fff;
 border: none;
 font-weight: bold;
 box-shadow: 0 2px 8px rgba(0,0,0,0.10);
 cursor: pointer;
}
@media (max-width: 600px) {
 .cornhole-container {
 padding: 0;
 }
 .cornhole-section {
 padding: 20px 4px 16px 4px;
 }
 .cornhole-end-round-btn {
 font-size: 1em;
 min-width: 0;
 padding: 10px 10px;
 }
 .cornhole-restart-btn {
 font-size: 1em;
 padding: 12px 12px;
 }
 .cornhole-score-row {
 gap: 8px;
 max-width: 220px;
 }
 .cornhole-score-box {
 width: 70px;
 font-size: 1.1em;
 }
}
.single .cover, .single .featured-image, .single .page-header__cover { display: none !important; }
&lt;/style>
&lt;div class="cornhole-container">
 &lt;!-- Team 1 Section -->
 &lt;div class="cornhole-section team1">
 &lt;div class="cornhole-title">Team 1&lt;/div>
 &lt;div class="cornhole-btn-row">
 &lt;button class="cornhole-btn">+1&lt;/button>
 &lt;button class="cornhole-btn">+3&lt;/button>
 &lt;/div>
 &lt;div class="cornhole-reset-row">
 &lt;button class="cornhole-btn cornhole-reset-btn">Reset Round&lt;/button>
 &lt;/div>
 &lt;div class="cornhole-score-row">
 &lt;div class="cornhole-score-col">
 &lt;label class="cornhole-label" for="team1-current">Current Round&lt;/label>
 &lt;input class="cornhole-score-box" id="team1-current" type="text" value="0" readonly />
 &lt;/div>
 &lt;div class="cornhole-score-col">
 &lt;label class="cornhole-label" for="team1-overall">Overall Score&lt;/label>
 &lt;input class="cornhole-score-box" id="team1-overall" type="text" value="0" readonly />
 &lt;/div>
 &lt;/div>
 &lt;!-- End Round button overlaps divider -->
 &lt;button class="cornhole-end-round-btn">End Round&lt;/button>
 &lt;/div>
 &lt;!-- Divider -->
 &lt;div class="cornhole-divider">&lt;/div>
 &lt;!-- Team 2 Section -->
 &lt;div class="cornhole-section team2">
 &lt;div class="cornhole-title">Team 2&lt;/div>
 &lt;div class="cornhole-btn-row">
 &lt;button class="cornhole-btn">+1&lt;/button>
 &lt;button class="cornhole-btn">+3&lt;/button>
 &lt;/div>
 &lt;div class="cornhole-reset-row">
 &lt;button class="cornhole-btn cornhole-reset-btn">Reset Round&lt;/button>
 &lt;/div>
 &lt;div class="cornhole-score-row">
 &lt;div class="cornhole-score-col">
 &lt;label class="cornhole-label" for="team2-current">Current Round&lt;/label>
 &lt;input class="cornhole-score-box" id="team2-current" type="text" value="0" readonly />
 &lt;/div>
 &lt;div class="cornhole-score-col">
 &lt;label class="cornhole-label" for="team2-overall">Overall Score&lt;/label>
 &lt;input class="cornhole-score-box" id="team2-overall" type="text" value="0" readonly />
 &lt;/div>
 &lt;/div>
 &lt;button class="cornhole-restart-btn">Restart Game&lt;/button>
 &lt;/div>
&lt;/div>
&lt;script>
document.addEventListener('DOMContentLoaded', function() {
 // Team 1
 const team1Current = document.getElementById('team1-current');
 const team1Overall = document.getElementById('team1-overall');
 const team1Btns = document.querySelectorAll('.team1 .cornhole-btn');
 const team1Reset = document.querySelector('.team1 .cornhole-reset-btn');

 // Team 2
 const team2Current = document.getElementById('team2-current');
 const team2Overall = document.getElementById('team2-overall');
 const team2Btns = document.querySelectorAll('.team2 .cornhole-btn');
 const team2Reset = document.querySelector('.team2 .cornhole-reset-btn');

 // End Round &amp; Restart
 const endRoundBtn = document.querySelector('.cornhole-end-round-btn');
 const restartBtn = document.querySelector('.cornhole-restart-btn');

 // Team 1: +1, +3
 team1Btns.forEach(btn => {
 if (btn.textContent === '+1') {
 btn.addEventListener('click', () => {
 team1Current.value = parseInt(team1Current.value, 10) + 1;
 });
 } else if (btn.textContent === '+3') {
 btn.addEventListener('click', () => {
 team1Current.value = parseInt(team1Current.value, 10) + 3;
 });
 }
 });
 // Team 1: Reset Round
 team1Reset.addEventListener('click', () => {
 team1Current.value = 0;
 });

 // Team 2: +1, +3
 team2Btns.forEach(btn => {
 if (btn.textContent === '+1') {
 btn.addEventListener('click', () => {
 team2Current.value = parseInt(team2Current.value, 10) + 1;
 });
 } else if (btn.textContent === '+3') {
 btn.addEventListener('click', () => {
 team2Current.value = parseInt(team2Current.value, 10) + 3;
 });
 }
 });
 // Team 2: Reset Round
 team2Reset.addEventListener('click', () => {
 team2Current.value = 0;
 });

 // End Round logic
 endRoundBtn.addEventListener('click', () => {
 const t1 = parseInt(team1Current.value, 10);
 const t2 = parseInt(team2Current.value, 10);
 if (t1 === t2) {
 // Tie: no points awarded
 } else if (t1 > t2) {
 team1Overall.value = parseInt(team1Overall.value, 10) + (t1 - t2);
 } else {
 team2Overall.value = parseInt(team2Overall.value, 10) + (t2 - t1);
 }
 team1Current.value = 0;
 team2Current.value = 0;
 });

 // Restart Game logic
 restartBtn.addEventListener('click', () => {
 team1Current.value = 0;
 team2Current.value = 0;
 team1Overall.value = 0;
 team2Overall.value = 0;
 });
});
&lt;/script></description><media:content xmlns:media="http://search.yahoo.com/mrss/" url="http://stringsandtines.com/code/cornhole/featured.jpg"/></item></channel></rss>