{
  "id": "photo-halftone",
  "name": "Halftone photograph",
  "kind": "photo",
  "shows": "A photograph printed whole as a one-ink halftone: round dots of the page's ink (or its accent, tint 1) on one 45 degree screen, on the page's surface as paper. Its own tone curve keeps a light photograph's near-whites as clean paper and its deepest shadows solid, with a dotted outline along the photograph's edges, so a pale object on a pale wall keeps its shape.",
  "suits": [
    "software",
    "ai",
    "design-tool",
    "gaming"
  ],
  "bestWith": "One clear subject in clear light on a plain ground (a product, an object, a building); high-key photographs print clean. A busy mid-grey texture (knitwear, foliage) prints as an even checker: pick another photograph. Coarse on purpose: never for a face read small.",
  "takes": "The <img> inside the frame (its largest srcset size, its alt, its object-position as the subject's place), else src, else data-src: the client's own photograph, or one from scripts/photos.mjs that prints well (\"prints\": true), credited in the footer with photos.mjs credits --adapted <id>.",
  "where": "One crafted moment on a software, AI, design-tool or gaming page: the page's one photograph band or a feature tile about the picture. Never over the hero photograph or a section's main photograph, never on a cafe, guesthouse or local business page, never with a caption under it.",
  "palettes": [
    "light",
    "dark",
    "colour"
  ],
  "touch": "A tap shows the hover state at the finger for 1.6 s; lifting the finger does not end it (checked at 390). Nothing moves on its own.",
  "reducedMotion": "The same still print; hover still answers, without easing.",
  "fallback": "The photograph itself, greyed into the palette (multiplied into light paper, screened on dark): shown under the canvas before the first frame and while the canvas is released off screen, and kept when WebGL is missing, the shader fails to compile or link, the shader uses a GLSL ES reserved word (refused by photo-kit's lint, so CPU WebGL shows what a GPU would), or the photograph's host sends no CORS headers. Checked with a broken shader and with a reserved word: the still shows, never an empty frame. With no photograph at all: the effects' palette ground.",
  "credits": "../photo-kit/photos.json",
  "credit": "In the footer's one credits line, never under the print: photos.mjs credits --out . --adapted <id>; for other photographs photoCredit() or creditsLine() in ../photo-kit/photo.js (author, licence linked, \"adapted\").",
  "demo": "demo.html",
  "motion": "None at rest and no entry: the print is there, finished, from its first frame.",
  "hover": "A loupe grows in under the cursor: a round lens with a hairline rim and a soft shadow shows the photograph itself, in its own colours, magnified 1.35 times.",
  "params": "pitch (dot spacing, 5 CSS px), angle, tint (0 ink, 1 accent), ground (1 the surface as paper, 0 the page), clean (shares under 0.1 print no dot), outline (dots along edges, 0.4), magnify, radius, clarity, contrast, exposure, focusX, focusY",
  "testedOn": [
    "lamp: product, Commons d88, LoMit, CC BY-SA 4.0 (high-key)",
    "bowls of beans: Commons c70, Alorin (high-key, white on white)",
    "chair at a window: Unsplash 311, Logan Adermatt (dark)",
    "room: picsum 625, Breather, Unsplash licence",
    "concrete: picsum 942, Carl Nenzen Loven, Unsplash licence"
  ],
  "runtime": "../photo-kit/photo.js: one canvas and one WebGL context per print, counted in fx.glBudget; at most 3 prints hold a context on a page (a fourth shows its still until one leaves the screen; a frame scrolling away gives way to one coming in); released 1.5 s after its frame leaves the screen; paused off screen and with the tab hidden; up to 2 canvas px per CSS px on a sharp screen, so the dots stay crisp; never over 1.5 MP; shader compiled off the main thread where KHR_parallel_shader_compile exists.",
  "cost": {
    "perPixel": "3 mipmapped reads (the photograph over a dot, a wider read for clarity, the edge map), one more inside the loupe; 2 cos and 2 sin; no noise, no loops",
    "renderScale": "up to 2 canvas px per CSS px, never over 1.5 MP (a 644 x 805 tile at DPR 2 renders at 1.7)",
    "contexts": 1
  },
  "for": "In the kit's gallery only, never on a page (references/effects-objects.md): no page prints, dithers or grades a photograph."
}
