app
Shotlog - Screenshot Log
Public Made by Adomby adom
See the shots your AI never showed you, and know it actually SAW them. adom-shotlog streams every screenshot the AI gathers into a live gallery (webview/pup/browser/phone), reports whether a human is really watching and on which surface, and ingests Adom Bridge child-window arrays via --meta.
← Commit history
Publish 0.29.1
7 files changed
+36−19
Cargo.lock+1−1@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "adom-shotlog"-version = "0.29.0"+version = "0.29.1" dependencies = [ "axum", "base64",
Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "adom-shotlog"-version = "0.29.0"+version = "0.29.1" edition = "2021" description = "Screenshot log viewer and CLI for Adom" license = "MIT"
VERSION+1−1@@ -1 +1 @@-0.29.0+0.29.1
bin/adom-shotlog⋯ 1 unchanged line ⋯
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "adom-shotlog",- "version": "0.29.0",+ "version": "0.29.1", "type": "app", "title": "Shotlog - Screenshot Log", "description": "See the shots your AI never showed you, and know it actually SAW them. adom-shotlog streams every screenshot the AI gathers into a live gallery (webview/pup/browser/phone), reports whether a human is really watching and on which surface, and ingests Adom Bridge child-window arrays via --meta.",
page.json+1−1@@ -1,6 +1,6 @@ { "slug": "adom-shotlog",- "version": "0.29.0",+ "version": "0.29.1", "type": "app", "title": "Shotlog - Screenshot Log", "description": "See the shots your AI never showed you, and know it actually SAW them. adom-shotlog streams every screenshot the AI gathers into a live gallery (webview/pup/browser/phone), reports whether a human is really watching and on which surface, and ingests Adom Bridge child-window arrays via --meta.",
src/html/index.html+31−14@@ -259,12 +259,13 @@ body.compact .card-popups .ph { padding-top: 4px; } .card-refbar .rb-ref { letter-spacing: .2px; } /* copy button (Ray, PR #5): hover-revealed like ⛶, never on the thumbnail */ .card-refbar .rb-copy svg { width: 13px; height: 13px; display: block; }-.card-refbar .rb-copy { margin-left: 4px; padding: 2px 4px; border-radius: 5px; cursor: pointer;+.card-refbar .rb-copy { margin-left: 2px; padding: 2px 5px; border-radius: 5px; cursor: pointer; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;- font: inherit; line-height: 1.5; color: var(--text3); background: transparent;- border: 1px solid var(--border-muted); opacity: 0; transition: opacity .12s, color .12s, border-color .12s; }+ font: inherit; line-height: 1.5; color: var(--accent-bright); background: rgba(0,184,176,.10);+ border: 1px solid rgba(0,184,176,.55); opacity: 1; transition: color .12s, border-color .12s, background .12s; }+/* Always visible (Ray, 2026-10-16: hover-revealed and grey, it was too faint to find). */ .shot-card:hover .card-refbar .rb-copy, .card-refbar .rb-copy:focus-visible { opacity: 1; }-.card-refbar .rb-copy:hover { color: var(--accent-bright); border-color: rgba(0,184,176,.5); }+.card-refbar .rb-copy:hover { color: #fff; background: rgba(0,184,176,.30); border-color: var(--accent-bright); } .card-refbar .rb-copy.done { opacity: 1; color: var(--accent-bright); border-color: rgba(0,184,176,.5); } @media (hover: none) { .card-refbar .rb-copy { opacity: .8; } } .card-refbar .rb-tag { color: var(--accent-bright); background: rgba(0,184,176,.12); border: 1px solid rgba(0,184,176,.45);@@ -1180,6 +1181,14 @@ body:not(.compact) .card-refbar .rb-cap { display: none; } // COMPACT mode hides it and reveals it as a hover overlay (the ⓘ chip on // the image), so the gallery is ~90% thumbnails. const info=document.createElement('div'); info.className='card-info';+ // Reveal the compact overlay BELOW the ref bar, never over it: the bar+ // holds the copy button and the caption pill, and an overlay covering+ // them blocked the copy button (Ray, 2026-10-16).+ const showInfo=()=>{+ const rb=c.querySelector('.card-refbar');+ info.style.top = rb ? (rb.offsetTop + rb.offsetHeight) + 'px' : '';+ info.classList.add('show'); window._hideTip&&window._hideTip();+ }; // For auto-captures the WHY is the headline: show the prompt the thread // was serving, and demote the generic "auto-captured: file.png" to a // small mono sub-line. Deliberate injects keep their description first.@@ -1283,14 +1292,6 @@ body:not(.compact) .card-refbar .rb-cap { display: none; } if (e.tag){ const tg=document.createElement('span'); tg.className='rb-tag'; tg.textContent=e.tag; tg.setAttribute('data-tooltip','Handle "'+e.tag+'" given by the AI that injected this shot (--tag). Say "'+e.tag+'" to mean exactly this shot.'); rb.appendChild(tg); }- if (e.auto_description && e.description) {- const cp=document.createElement('span'); cp.className='rb-cap'; cp.textContent=e.description;- cp.setAttribute('aria-label','Caption: '+e.description);- // Same reveal as the ⓘ: hover shows the full info overlay (caption,- // prompt, file, chips); click toggles it for touch.- cp.addEventListener('mouseenter', ()=>{ info.classList.add('show'); window._hideTip&&window._hideTip(); });- cp.addEventListener('click', ev=>{ ev.stopPropagation(); info.classList.toggle('show'); });- rb.appendChild(cp); } // Copy the WHOLE reference, "#158 hero-final", not just one half (Ray, // PR #5): the ref is globally unambiguous and the handle is what a human // actually says, so pasting both lets the AI resolve it either way and@@ -1310,6 +1311,21 @@ body:not(.compact) .card-refbar .rb-cap { display: none; } } else { legacyCopy(txt, done); } }); rb.appendChild(cp); }+ // The caption pill comes AFTER the copy button (Ray, 2026-10-16): the+ // button copies "#id handle", so it sits beside them, not past the caption.+ if (e.auto_description && e.description) {+ const cp=document.createElement('span'); cp.className='rb-cap'; cp.textContent=e.description;+ cp.setAttribute('aria-label','Caption: '+e.description);+ // Same reveal as the ⓘ: hover shows the full info overlay (caption,+ // prompt, file, chips); click toggles it for touch.+ // Hover INTENT, not a bare mouseenter: the pointer crosses this pill on+ // its way to the copy button, and an instant overlay got in the way.+ let capTimer=null;+ cp.addEventListener('mouseenter', ()=>{ capTimer=setTimeout(showInfo, 350); });+ cp.addEventListener('mouseleave', ()=>{ clearTimeout(capTimer); });+ cp.addEventListener('click', ev=>{ ev.stopPropagation(); clearTimeout(capTimer);+ if (info.classList.contains('show')) info.classList.remove('show'); else showInfo(); });+ rb.appendChild(cp); } c.appendChild(rb); } // info (hidden in compact) -> refbar -> imgWrap (appended below) // COMPACT mode's reveal chip: hover (or tap, on touch) the ⓘ on the image // to overlay the full info block; it hides again when the pointer leaves@@ -1319,8 +1335,9 @@ body:not(.compact) .card-refbar .rb-cap { display: none; } // No data-tooltip on the ⓘ: its hover REVEALS the info overlay, and a // tooltip 600ms later landed right on top of what the human was reading. infoHot.title='';- infoHot.addEventListener('mouseenter', ()=>{ info.classList.add('show'); window._hideTip&&window._hideTip(); });- infoHot.addEventListener('click', ev=>{ ev.stopPropagation(); info.classList.toggle('show'); });+ infoHot.addEventListener('mouseenter', showInfo);+ infoHot.addEventListener('click', ev=>{ ev.stopPropagation();+ if (info.classList.contains('show')) info.classList.remove('show'); else showInfo(); }); c.addEventListener('mouseleave', ()=>info.classList.remove('show')); imgWrap.appendChild(infoHot); // Additional path: jump STRAIGHT to fullscreen, no modal first. The click