theseus/bundled-addons/screenshot/editor.html

118 lines
6.4 KiB
HTML
Raw Normal View History

feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Screenshot editor</title>
<link rel="stylesheet" href="editor.css">
</head>
<body>
<div class="topbar">
<button class="btn" id="back" title="Back to sidebar panel">
feat(theseus/screenshot): 0.6.0 — crop + mosaic redaction, right-anchored sidebar controls, real shutter+print sounds Editor: - Crop tool restored — drag to select, marquee sits with a dashed acid border and a dimmed backdrop for the area you'll discard, then the topbar shows Apply crop / Cancel. Applying trims #base to the rect, resets undo (dimensions changed), and drops back into the select tool. Enter / Esc keyboard shortcuts while a crop is pending. - Blur / mosaic redaction tool back — drag a rectangle, editor downsamples that region of #base to ~12-block granularity and paints the blocks back nearest-neighbour. Commits directly (no confirm step). - Sidebar-window controls (Back, name, Copy, Save, Sound, Maximize) reflow: Back + name on the left, Copy + Save + Sound + Maximize on the right so the "put the sidebar back to normal size" affordance lives where users expect it. Toolbar's drawing tools stay centred. - Back arrow icon swapped from a chevron to a proper flat arrow (line + arrowhead), matching the new browser back/forward glyphs. Sounds — modeled on Firefox Screenshots' feedback rather than beeps: - Shutter is now a real photoshoot click: two mirror-slaps built from a band-passed noise burst (metallic ping) plus a very short square-wave thud each. Sounds like a camera, not a beep. - Copy is a two-chirp "printer feed" — filtered noise burst on top of a sine chirp per beat, staccato ascending pair. Same shape Firefox Easy Screenshot uses for "copied to clipboard". - Save keeps its ascending triad; Discard keeps its descending pair; new small ascending pair for Apply crop. Chrome: - Browser Back / Forward chevrons (M10 3 L5 8 L10 13 — two segments meeting at a point, no shaft) replaced with straight-arrow glyphs (line + arrowhead). Reads as a navigation arrow, not an angle bracket. Bundled but not shipped separately — parent session OTA-signs and pushes.
2026-09-09 10:24:03 +02:00
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M13 8H3M6 5L3 8l3 3"/></svg>
feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
</button>
<span class="name" id="name">screenshot</span>
feat(theseus/screenshot): 0.6.0 — crop + mosaic redaction, right-anchored sidebar controls, real shutter+print sounds Editor: - Crop tool restored — drag to select, marquee sits with a dashed acid border and a dimmed backdrop for the area you'll discard, then the topbar shows Apply crop / Cancel. Applying trims #base to the rect, resets undo (dimensions changed), and drops back into the select tool. Enter / Esc keyboard shortcuts while a crop is pending. - Blur / mosaic redaction tool back — drag a rectangle, editor downsamples that region of #base to ~12-block granularity and paints the blocks back nearest-neighbour. Commits directly (no confirm step). - Sidebar-window controls (Back, name, Copy, Save, Sound, Maximize) reflow: Back + name on the left, Copy + Save + Sound + Maximize on the right so the "put the sidebar back to normal size" affordance lives where users expect it. Toolbar's drawing tools stay centred. - Back arrow icon swapped from a chevron to a proper flat arrow (line + arrowhead), matching the new browser back/forward glyphs. Sounds — modeled on Firefox Screenshots' feedback rather than beeps: - Shutter is now a real photoshoot click: two mirror-slaps built from a band-passed noise burst (metallic ping) plus a very short square-wave thud each. Sounds like a camera, not a beep. - Copy is a two-chirp "printer feed" — filtered noise burst on top of a sine chirp per beat, staccato ascending pair. Same shape Firefox Easy Screenshot uses for "copied to clipboard". - Save keeps its ascending triad; Discard keeps its descending pair; new small ascending pair for Apply crop. Chrome: - Browser Back / Forward chevrons (M10 3 L5 8 L10 13 — two segments meeting at a point, no shaft) replaced with straight-arrow glyphs (line + arrowhead). Reads as a navigation arrow, not an angle bracket. Bundled but not shipped separately — parent session OTA-signs and pushes.
2026-09-09 10:24:03 +02:00
<!-- Crop mode splits the topbar into a confirm/cancel prompt while the
user is dragging a crop rectangle. Everything else in the topbar
fades in and out around these two buttons. -->
<button class="btn wide" id="apply-crop" hidden title="Apply the crop (Enter)">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8l3 3 7-7"/></svg>
<span>Apply crop</span>
</button>
<button class="btn wide" id="cancel-crop" hidden title="Cancel crop (Esc)">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg>
<span>Cancel</span>
</button>
feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
<span class="spacer"></span>
<button class="btn wide" id="copy" title="Copy PNG to clipboard (Ctrl+C)">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="4" y="4" width="9" height="10"/><path d="M3 12V3h9"/></svg>
<span>Copy</span>
</button>
<button class="btn wide primary" id="save" title="Save PNG (Ctrl+S)">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M8 2v9M4 7l4 4 4-4M2 14h12"/></svg>
<span>Save</span>
</button>
feat(theseus/screenshot): 0.6.0 — crop + mosaic redaction, right-anchored sidebar controls, real shutter+print sounds Editor: - Crop tool restored — drag to select, marquee sits with a dashed acid border and a dimmed backdrop for the area you'll discard, then the topbar shows Apply crop / Cancel. Applying trims #base to the rect, resets undo (dimensions changed), and drops back into the select tool. Enter / Esc keyboard shortcuts while a crop is pending. - Blur / mosaic redaction tool back — drag a rectangle, editor downsamples that region of #base to ~12-block granularity and paints the blocks back nearest-neighbour. Commits directly (no confirm step). - Sidebar-window controls (Back, name, Copy, Save, Sound, Maximize) reflow: Back + name on the left, Copy + Save + Sound + Maximize on the right so the "put the sidebar back to normal size" affordance lives where users expect it. Toolbar's drawing tools stay centred. - Back arrow icon swapped from a chevron to a proper flat arrow (line + arrowhead), matching the new browser back/forward glyphs. Sounds — modeled on Firefox Screenshots' feedback rather than beeps: - Shutter is now a real photoshoot click: two mirror-slaps built from a band-passed noise burst (metallic ping) plus a very short square-wave thud each. Sounds like a camera, not a beep. - Copy is a two-chirp "printer feed" — filtered noise burst on top of a sine chirp per beat, staccato ascending pair. Same shape Firefox Easy Screenshot uses for "copied to clipboard". - Save keeps its ascending triad; Discard keeps its descending pair; new small ascending pair for Apply crop. Chrome: - Browser Back / Forward chevrons (M10 3 L5 8 L10 13 — two segments meeting at a point, no shaft) replaced with straight-arrow glyphs (line + arrowhead). Reads as a navigation arrow, not an angle bracket. Bundled but not shipped separately — parent session OTA-signs and pushes.
2026-09-09 10:24:03 +02:00
<button class="btn" id="toggle-sound" title="Toggle sound"></button>
<button class="btn" id="toggle-max" title="Expand the sidebar to full window / restore">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 6V2h4M14 6V2h-4M2 10v4h4M14 10v4h-4"/></svg>
</button>
feat(theseus/screenshot): 0.6.1 — text tool fix, category wrap, sidebar close X Four user reports from the 0.6.0 rollout: - Text tool never committed. openTextInput placed the box correctly but a couple of Chromium quirks stopped a normal type-Enter cycle: focus() called synchronously right after appendChild lost the race in some builds, and the input's own mousedown / click was bubbling through to #base and re-firing openTextInput on every subsequent keystroke click-through, so what looked like "nothing happens" was actually "a new empty box spawned on top of the last one every time". Now: focus after requestAnimationFrame, contain pointerdown / mousedown / click inside the input so they don't bubble to the canvas, track the font size on the state so commit uses the same one openTextInput measured against, and preventDefault on the base pointerdown so Chromium doesn't reset focus back to <body>. - Toolbar wrapped one dot at a time when the sidebar was narrow (a lonely thin/medium/thick width would jump to a second row while the swatches stayed above it). Toolbar items are now wrapped in `<div class="tgroup">` per category — tools / swatches / widths / undo-redo — with `flex: 0 0 auto`, so a whole row wraps as a unit and lands cleanly under the previous one. `gap: 10px / row-gap: 6px` keeps the visual grouping obvious. - No way to close the sidebar without hunting for the dock icon. Added an X button in the top-right of both the sidebar panel and the editor toolbar. Both wire through a new `silentmode.sidebar.close()` preload method that calls the existing `sidebar-close` IPC. - Tightened the pointerdown text branch so preventDefault + explicit focus-after-frame make the click-through races impossible. Bundled but not shipped separately — parent session signs and pushes.
2026-09-09 10:55:21 +02:00
<button class="btn" id="close-sidebar" title="Close the sidebar">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg>
</button>
feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
</div>
feat(theseus/screenshot): 0.6.1 — text tool fix, category wrap, sidebar close X Four user reports from the 0.6.0 rollout: - Text tool never committed. openTextInput placed the box correctly but a couple of Chromium quirks stopped a normal type-Enter cycle: focus() called synchronously right after appendChild lost the race in some builds, and the input's own mousedown / click was bubbling through to #base and re-firing openTextInput on every subsequent keystroke click-through, so what looked like "nothing happens" was actually "a new empty box spawned on top of the last one every time". Now: focus after requestAnimationFrame, contain pointerdown / mousedown / click inside the input so they don't bubble to the canvas, track the font size on the state so commit uses the same one openTextInput measured against, and preventDefault on the base pointerdown so Chromium doesn't reset focus back to <body>. - Toolbar wrapped one dot at a time when the sidebar was narrow (a lonely thin/medium/thick width would jump to a second row while the swatches stayed above it). Toolbar items are now wrapped in `<div class="tgroup">` per category — tools / swatches / widths / undo-redo — with `flex: 0 0 auto`, so a whole row wraps as a unit and lands cleanly under the previous one. `gap: 10px / row-gap: 6px` keeps the visual grouping obvious. - No way to close the sidebar without hunting for the dock icon. Added an X button in the top-right of both the sidebar panel and the editor toolbar. Both wire through a new `silentmode.sidebar.close()` preload method that calls the existing `sidebar-close` IPC. - Tightened the pointerdown text branch so preventDefault + explicit focus-after-frame make the click-through races impossible. Bundled but not shipped separately — parent session signs and pushes.
2026-09-09 10:55:21 +02:00
<!-- Toolbar rows are grouped so that when the sidebar is too narrow to
hold everything, whole categories wrap together (tools stay with
tools, swatches with swatches, widths with widths, history with
history) instead of one dot spilling to a lonely second row. -->
feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
<div class="toolbar">
feat(theseus/screenshot): 0.6.1 — text tool fix, category wrap, sidebar close X Four user reports from the 0.6.0 rollout: - Text tool never committed. openTextInput placed the box correctly but a couple of Chromium quirks stopped a normal type-Enter cycle: focus() called synchronously right after appendChild lost the race in some builds, and the input's own mousedown / click was bubbling through to #base and re-firing openTextInput on every subsequent keystroke click-through, so what looked like "nothing happens" was actually "a new empty box spawned on top of the last one every time". Now: focus after requestAnimationFrame, contain pointerdown / mousedown / click inside the input so they don't bubble to the canvas, track the font size on the state so commit uses the same one openTextInput measured against, and preventDefault on the base pointerdown so Chromium doesn't reset focus back to <body>. - Toolbar wrapped one dot at a time when the sidebar was narrow (a lonely thin/medium/thick width would jump to a second row while the swatches stayed above it). Toolbar items are now wrapped in `<div class="tgroup">` per category — tools / swatches / widths / undo-redo — with `flex: 0 0 auto`, so a whole row wraps as a unit and lands cleanly under the previous one. `gap: 10px / row-gap: 6px` keeps the visual grouping obvious. - No way to close the sidebar without hunting for the dock icon. Added an X button in the top-right of both the sidebar panel and the editor toolbar. Both wire through a new `silentmode.sidebar.close()` preload method that calls the existing `sidebar-close` IPC. - Tightened the pointerdown text branch so preventDefault + explicit focus-after-frame make the click-through races impossible. Bundled but not shipped separately — parent session signs and pushes.
2026-09-09 10:55:21 +02:00
<div class="tgroup" role="group" aria-label="Tools">
<button class="tool active" data-tool="select" title="Select (no tool)">
<svg viewBox="0 0 16 16" fill="currentColor"><path d="M3 2l10 5-4 1-1 4z"/></svg>
</button>
<button class="tool" data-tool="crop" title="Crop (C)">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M4 1v11h11M1 4h11v11"/></svg>
</button>
<button class="tool" data-tool="arrow" title="Arrow (A)">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3 13L13 3M13 3H8M13 3v5"/></svg>
</button>
<button class="tool" data-tool="rect" title="Rectangle (R)">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2.5" y="3.5" width="11" height="9"/></svg>
</button>
<button class="tool" data-tool="ellipse" title="Ellipse (O)">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><ellipse cx="8" cy="8" rx="5.5" ry="4"/></svg>
</button>
<button class="tool" data-tool="pen" title="Pen (P)">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 14c1-3 3-6 6-8s5-3 6-3l-3 4c-2 1-4 3-6 4s-2 2-3 3z"/></svg>
</button>
<button class="tool" data-tool="text" title="Text (T)">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M3 3h10M8 3v10M6 13h4"/></svg>
</button>
<button class="tool" data-tool="blur" title="Blur / mosaic redaction (B)">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2.5" y="2.5" width="11" height="11"/><path d="M5 6h1M8 6h1M11 6h1M5 9h1M8 9h1M11 9h1M5 12h1M8 12h1M11 12h1"/></svg>
</button>
</div>
feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
feat(theseus/screenshot): 0.6.1 — text tool fix, category wrap, sidebar close X Four user reports from the 0.6.0 rollout: - Text tool never committed. openTextInput placed the box correctly but a couple of Chromium quirks stopped a normal type-Enter cycle: focus() called synchronously right after appendChild lost the race in some builds, and the input's own mousedown / click was bubbling through to #base and re-firing openTextInput on every subsequent keystroke click-through, so what looked like "nothing happens" was actually "a new empty box spawned on top of the last one every time". Now: focus after requestAnimationFrame, contain pointerdown / mousedown / click inside the input so they don't bubble to the canvas, track the font size on the state so commit uses the same one openTextInput measured against, and preventDefault on the base pointerdown so Chromium doesn't reset focus back to <body>. - Toolbar wrapped one dot at a time when the sidebar was narrow (a lonely thin/medium/thick width would jump to a second row while the swatches stayed above it). Toolbar items are now wrapped in `<div class="tgroup">` per category — tools / swatches / widths / undo-redo — with `flex: 0 0 auto`, so a whole row wraps as a unit and lands cleanly under the previous one. `gap: 10px / row-gap: 6px` keeps the visual grouping obvious. - No way to close the sidebar without hunting for the dock icon. Added an X button in the top-right of both the sidebar panel and the editor toolbar. Both wire through a new `silentmode.sidebar.close()` preload method that calls the existing `sidebar-close` IPC. - Tightened the pointerdown text branch so preventDefault + explicit focus-after-frame make the click-through races impossible. Bundled but not shipped separately — parent session signs and pushes.
2026-09-09 10:55:21 +02:00
<div class="tgroup" role="group" aria-label="Colours">
<button class="swatch active" data-color="#ff3b30" style="background:#ff3b30" title="Red"></button>
<button class="swatch" data-color="#d6ff3d" style="background:#d6ff3d" title="Acid"></button>
<button class="swatch" data-color="#ffcc00" style="background:#ffcc00" title="Yellow"></button>
<button class="swatch" data-color="#0aa8ff" style="background:#0aa8ff" title="Blue"></button>
<button class="swatch" data-color="#ffffff" style="background:#ffffff" title="White"></button>
<button class="swatch" data-color="#000000" style="background:#000000" title="Black"></button>
</div>
feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
feat(theseus/screenshot): 0.6.1 — text tool fix, category wrap, sidebar close X Four user reports from the 0.6.0 rollout: - Text tool never committed. openTextInput placed the box correctly but a couple of Chromium quirks stopped a normal type-Enter cycle: focus() called synchronously right after appendChild lost the race in some builds, and the input's own mousedown / click was bubbling through to #base and re-firing openTextInput on every subsequent keystroke click-through, so what looked like "nothing happens" was actually "a new empty box spawned on top of the last one every time". Now: focus after requestAnimationFrame, contain pointerdown / mousedown / click inside the input so they don't bubble to the canvas, track the font size on the state so commit uses the same one openTextInput measured against, and preventDefault on the base pointerdown so Chromium doesn't reset focus back to <body>. - Toolbar wrapped one dot at a time when the sidebar was narrow (a lonely thin/medium/thick width would jump to a second row while the swatches stayed above it). Toolbar items are now wrapped in `<div class="tgroup">` per category — tools / swatches / widths / undo-redo — with `flex: 0 0 auto`, so a whole row wraps as a unit and lands cleanly under the previous one. `gap: 10px / row-gap: 6px` keeps the visual grouping obvious. - No way to close the sidebar without hunting for the dock icon. Added an X button in the top-right of both the sidebar panel and the editor toolbar. Both wire through a new `silentmode.sidebar.close()` preload method that calls the existing `sidebar-close` IPC. - Tightened the pointerdown text branch so preventDefault + explicit focus-after-frame make the click-through races impossible. Bundled but not shipped separately — parent session signs and pushes.
2026-09-09 10:55:21 +02:00
<div class="tgroup" role="group" aria-label="Widths">
<button class="width" data-width="3" title="Thin"><span class="dot" style="width:4px;height:4px"></span></button>
<button class="width active" data-width="5" title="Medium"><span class="dot" style="width:7px;height:7px"></span></button>
<button class="width" data-width="9" title="Thick"><span class="dot" style="width:11px;height:11px"></span></button>
</div>
feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
feat(theseus/screenshot): 0.6.1 — text tool fix, category wrap, sidebar close X Four user reports from the 0.6.0 rollout: - Text tool never committed. openTextInput placed the box correctly but a couple of Chromium quirks stopped a normal type-Enter cycle: focus() called synchronously right after appendChild lost the race in some builds, and the input's own mousedown / click was bubbling through to #base and re-firing openTextInput on every subsequent keystroke click-through, so what looked like "nothing happens" was actually "a new empty box spawned on top of the last one every time". Now: focus after requestAnimationFrame, contain pointerdown / mousedown / click inside the input so they don't bubble to the canvas, track the font size on the state so commit uses the same one openTextInput measured against, and preventDefault on the base pointerdown so Chromium doesn't reset focus back to <body>. - Toolbar wrapped one dot at a time when the sidebar was narrow (a lonely thin/medium/thick width would jump to a second row while the swatches stayed above it). Toolbar items are now wrapped in `<div class="tgroup">` per category — tools / swatches / widths / undo-redo — with `flex: 0 0 auto`, so a whole row wraps as a unit and lands cleanly under the previous one. `gap: 10px / row-gap: 6px` keeps the visual grouping obvious. - No way to close the sidebar without hunting for the dock icon. Added an X button in the top-right of both the sidebar panel and the editor toolbar. Both wire through a new `silentmode.sidebar.close()` preload method that calls the existing `sidebar-close` IPC. - Tightened the pointerdown text branch so preventDefault + explicit focus-after-frame make the click-through races impossible. Bundled but not shipped separately — parent session signs and pushes.
2026-09-09 10:55:21 +02:00
<div class="tgroup" role="group" aria-label="History">
<button class="btn" id="undo" title="Undo (Ctrl+Z)" disabled>
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M3 8c0-3 2-5 5-5s5 2 5 5-2 5-5 5"/><path d="M6 5L3 8l3 3"/></svg>
</button>
<button class="btn" id="redo" title="Redo (Ctrl+Shift+Z)" disabled>
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M13 8c0-3-2-5-5-5S3 5 3 8s2 5 5 5"/><path d="M10 5l3 3-3 3"/></svg>
</button>
</div>
feat(theseus/screenshot): 0.5.0 — sidebar-first editor, direct save/copy, sounds Two problems the old editor kept hitting: - __pending drain race: opening the editor a second time (refresh, back-and- forth navigation) found the storage entry already consumed and bailed to a blank canvas silently. - Cross-origin img loading: editor.html at file:///…/addons/screenshot/ loading a scratch PNG at file:///…/addons-data/ counts as cross-origin under Chromium's file-URL policy; setting crossOrigin="anonymous" made the load fail outright. Rebuilt editor v2: - Load path is idempotent: silentmode.invoke("getBytes", {name}) → addon reads the scratch file and returns a data URL. No __pending drain, no cross-origin trickery — data: URLs are same-origin and never taint the canvas, so getImageData / toBlob keep working. - Two-canvas model (#base + #over, over is pointer-events:none) so live previews don't cost a full re-composite per mousemove. - Tools: cursor, arrow, rect, ellipse, pen, text. 6 swatches, 3 widths, undo / redo (25-deep). Copy + Save at the top bar. Back and Maximize buttons in the same top bar so navigation controls stay reachable when the toolbar wraps at narrow widths. - Keyboard: A/R/O/P/T select tool, Esc = cursor, Ctrl+Z/Shift+Z undo/redo, Ctrl+S save, Ctrl+C copy. - Toast surface for save/copy/error feedback. Sidebar panel gains a direct raw-save path so the user can copy or save the capture without entering the editor: - Two-row actions: [Copy] [Save] on top, [Discard] [Edit] below. - Copy uses navigator.clipboard.write(ClipboardItem); Save uses <a download> with a Blob URL — same path Chromium's will-download tracker already handles, so the file lands in Downloads and the chip updates like any other save. Inline "clear all" confirmation replaces the native confirm() — the old system-modal opened over the tab area (out of the sidebar's visual context) and looked like Windows 95. Now a compact red strip appears under the Recent header with Cancel / Delete buttons. Sounds + a sound-on/off toggle in both surfaces: - Web Audio oscillator-synthesized (no .wav shipped): shutter click on capture, two-tone bloop on copy, descending pair on discard/back, ascending triad on save. - Preference stored in silentmode.storage under "soundOn" (default on), shared between the panel and the editor. Simplifications: - Dropped the addon's "arm" onMessage handler (superseded by getBytes). - Manifest capabilities: sidebar-panel + capture-tab (no open-tab, no toolbar-menu). Bundled but not shipped — parent session handles the OTA sign + push.
2026-09-09 00:56:41 +02:00
</div>
<div class="board" id="board">
<div class="empty" id="empty">
<div>Loading capture…</div>
</div>
<div class="stage" id="stage" hidden>
<canvas id="base"></canvas>
<canvas id="over"></canvas>
</div>
</div>
<div class="toast" id="toast"></div>
<a id="download-link" style="display:none"></a>
<script src="editor.js"></script>
</body>
</html>