skill
Adom UI Design System
Public Made by Adomby adom
How the AI builds and tests interfaces people love to use in Adom. Ships as one installable skill that bundles focused skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps, clickable-paths).
master
John Lauer
2.2.0: dash-screenshot - capture ONLY your dashboard's webview pane in ah, not the whole window, with the tool
6a6d5d3
1mo ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
#!/usr/bin/env python3
"""Capture ONLY a dock dashboard's webview pane inside ah.
A full-window hd_shot spends ~80% of its pixels on ah's chrome. This activates your tab,
reads your iframe's rect from the shell target, takes the shot, derives the scale from
hd_shot's OWN windowOuter metadata (never hardcoded), and crops to your pane.
python3 shot-webview.py --tab "Parts Search" --slug dock-parts-search \
--thread "my ai thread" --out /tmp/frame.png
... --box 33,160,216,240,red --box 249,160,424,240,lime # your page's coords
"""
import argparse, json, subprocess, sys
def bridge(verb, payload, thread, reason):
cmd = ['adom-bridge', '--target', 'AdomLapper', verb, json.dumps(payload),
'--ai-thread', thread, '--reason', reason]
p = subprocess.run(cmd, capture_output=True, text=True, timeout=180)
try:
return json.loads(p.stdout)
except Exception:
sys.exit('bridge call failed: ' + (p.stdout or p.stderr)[:400])
def cdp(js, target, thread, reason):
r = bridge('hd_api', {"method": "POST", "path": "/cdp-eval",
"body": {"target": target, "js": js}}, thread, reason)
return (r.get('body') or {}).get('value')
def main():
ap = argparse.ArgumentParser()
ap.add_argument('--tab', required=True, help='tab name exactly as the tab strip shows it')
ap.add_argument('--slug', required=True, help='a unique substring of your iframe src, e.g. your dock slug')
ap.add_argument('--thread', required=True, help='your ai thread name, for the activity log')
ap.add_argument('--out', default='/tmp/webview.png')
ap.add_argument('--pad', type=int, default=0, help='extra px of ah chrome to keep around the pane')
ap.add_argument('--box', action='append', default=[],
help='x,y,w,h,colour in YOUR page coordinates; repeatable')
a = ap.parse_args()
# 1. ACTIVATE. An unforegrounded tab reports zero-height rects and SPECIFIED css.
act = cdp("""(() => {
const t = [...document.querySelectorAll('.tab-bar .tab')]
.find(x => ((x.querySelector('span.tab-name')||{}).textContent||'').trim() === %s);
if (!t) return 'NOTAB';
if (!t.classList.contains('active')) t.click();
return 'active';
})()""" % json.dumps(a.tab), 'shell', a.thread,
f'activate {a.tab} before measuring, an unforegrounded tab measures wrong')
if act != 'active':
sys.exit(f'could not activate tab {a.tab!r}: {act}')
# 2. RECT, from the shell. Your own page cannot see where it sits in the window.
raw = cdp("""(() => {
const f = [...document.querySelectorAll('iframe')]
.find(x => (x.getAttribute('src')||'').includes(%s));
if (!f) return 'NOFRAME';
const r = f.getBoundingClientRect();
return JSON.stringify({x:Math.round(r.x), y:Math.round(r.y),
w:Math.round(r.width), h:Math.round(r.height),
shellW:innerWidth, dpr:devicePixelRatio});
})()""" % json.dumps(a.slug), 'shell', a.thread,
f'read the {a.slug} pane rect for a webview-only capture')
if not raw or raw == 'NOFRAME':
sys.exit(f'no iframe matching {a.slug!r}')
rect = json.loads(raw)
if rect['w'] == 0 or rect['h'] == 0:
sys.exit('pane rect is zero: the tab did not actually foreground')
# 3. SHOT, then scale from the RETURNED metadata. Never hardcode a scale or an origin.
shot = bridge('hd_shot', {"region": "full"}, a.thread, f'capture the {a.tab} pane')
safe = shot.get('localSafePath') or shot.get('safePath')
if not safe:
sys.exit('hd_shot did not return localSafePath: ' + json.dumps(shot)[:300])
from PIL import Image, ImageDraw
im = Image.open(safe).convert('RGB')
# Scale from the SHELL'S CSS VIEWPORT WIDTH, because the rect above is in CSS px.
# NOT from hd_shot's windowOuter: that is the OS window in PHYSICAL px (2582 where the
# CSS viewport is 1706 at dpr 1.5), and using it produces a crop about 34% too small
# that still looks like a plausible picture of a dashboard. Measured, not assumed.
scale = im.width / float(rect['shellW'])
if a.box:
d = ImageDraw.Draw(im)
for spec in a.box:
x, y, w, h, colour = spec.split(',')
x, y, w, h = (int(v) for v in (x, y, w, h))
d.rectangle([(rect['x']+x)*scale, (rect['y']+y)*scale,
(rect['x']+x+w)*scale, (rect['y']+y+h)*scale],
outline=colour.strip(), width=3)
p = a.pad
im.crop((max(0, int((rect['x']-p)*scale)), max(0, int((rect['y']-p)*scale)),
min(im.width, int((rect['x']+rect['w']+p)*scale)),
min(im.height, int((rect['y']+rect['h']+p)*scale)))).save(a.out)
print(json.dumps({"out": a.out, "paneRect": rect,
"scale": round(scale, 4), "fullForShotlog": shot.get('localFullPath')}, indent=1))
if __name__ == '__main__':
main()