@@ -19,6 +19,28 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
<button type="button" class="ge-btn ge-btn-sm" id="ge-pen-cancel" title="Cancel path (Escape)"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m18 6-12 12M6 6l12 12"/></svg> Cancel</button>
</div>
</div>
<div id="ge-liquify-section" style="display:none;">
<div class="ge-section-title">Liquify</div>
<div class="ge-control-row">
<label for="ge-liquify-mode">Mode</label>
<select id="ge-liquify-mode" class="ge-ctl-select">
<option value="push">Push</option>
<option value="twirl">Twirl</option>
<option value="pucker">Pucker</option>
<option value="bloat">Bloat</option>
<option value="smooth">Smooth</option>
</select>
</div>
<div class="ge-control-row ge-eraser-row">
<label><span id="ge-liquify-size-label">120px</span></label>
<input type="range" id="ge-liquify-size" min="10" max="600" value="120" />
</div>
<div class="ge-control-row ge-eraser-row">
<label>Strength <span id="ge-liquify-strength-label">50%</span></label>
<input type="range" id="ge-liquify-strength" min="1" max="100" value="50" />
</div>
<div class="ge-control-row ge-liquify-hint">Drag on the canvas to warp pixels. One undo step per stroke.</div>
</div>
<div class="ge-layer-geometry-section" id="ge-layer-geometry-section">
<div class="ge-section-title"><span>Position</span><span id="ge-layer-geometry-name"></span></div>
<div class="ge-layer-geometry-grid">
@@ -33,31 +55,105 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
<label>Color</label>
<input type="color" class="ge-color-picker" value=" ${ color } " />
</div>
<div class="ge-control-row">
<label>Size <span class="ge-size-label"> ${ brushSize } px</span></label>
<div class="ge-control-row ge-brush-size-row ">
<label><span class="ge-size-label"> ${ brushSize } px</span></label>
<input type="range" class="ge-size-slider" min="0" max="1000" value=" ${ brushSliderValue } " />
<span class="ge-brush-more-wrap">
<button type="button" class="ge-btn ge-btn-sm ge-brush-more-btn" id="ge-brush-more" aria-haspopup="true" aria-expanded="false" title="More brush options (spacing, smoothing, blend, opacity, pen pressure)" aria-label="More brush options">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>
</button>
<div class="ge-brush-more-menu" id="ge-brush-more-menu" hidden>
<div class="ge-section-title">Stroke</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-brush-preview-spacing" aria-hidden="true"></span>
<label>Spacing <span id="ge-brush-spacing-label">15%</span></label>
<input type="range" id="ge-brush-spacing" min="1" max="100" value="15" />
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-brush-preview-smoothing" aria-hidden="true"></span>
<label>Smoothing <span id="ge-brush-smoothing-label">25%</span></label>
<input type="range" id="ge-brush-smoothing" min="0" max="95" value="25" />
</div>
<div class="ge-control-row">
<label for="ge-brush-blend">Blend</label>
<select id="ge-brush-blend">
<option value="source-over">Normal</option><option value="multiply">Multiply</option>
<option value="screen">Screen</option><option value="overlay">Overlay</option>
<option value="soft-light">Soft Light</option><option value="color">Color</option>
</select>
</div>
<div class="ge-brush-stroke-group" data-stroke-tool="brush">
<div class="ge-section-title" id="ge-stroke-title-brush">Brush</div>
<div class="ge-control-row ge-eraser-row" id="ge-brush-opacity-row">
<span class="ge-eraser-preview" id="ge-brush-preview-opacity" aria-hidden="true"></span>
<label>Opacity <span id="ge-brush-opacity-label">100%</span></label>
<input type="range" id="ge-brush-opacity" min="10" max="100" value="100" />
</div>
<div class="ge-control-row ge-eraser-row" id="ge-brush-flow-row">
<span class="ge-eraser-preview" id="ge-brush-preview-flow" aria-hidden="true"></span>
<label>Flow <span id="ge-brush-flow-label">100%</span></label>
<input type="range" id="ge-brush-flow" min="5" max="100" value="100" />
</div>
<div class="ge-control-row ge-eraser-row" id="ge-brush-softness-row">
<span class="ge-eraser-preview" id="ge-brush-preview-softness" aria-hidden="true"></span>
<label>Softness <span id="ge-brush-softness-label">100%</span></label>
<input type="range" id="ge-brush-softness" min="0" max="300" value="100" title="Soft brush edge — blurs the stroke's alpha for a feathered fade at the perimeter." />
</div>
</div>
<div class="ge-brush-stroke-group" data-stroke-tool="eraser">
<div class="ge-section-title">Eraser</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-eraser-preview-opacity" aria-hidden="true"></span>
<label>Opacity <span id="ge-eraser-opacity-label">100%</span></label>
<input type="range" id="ge-eraser-opacity" min="10" max="100" value="100" />
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-eraser-preview-flow" aria-hidden="true"></span>
<label>Flow <span id="ge-eraser-flow-label">100%</span></label>
<input type="range" id="ge-eraser-flow" min="5" max="100" value="100" />
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-eraser-preview-softness" aria-hidden="true"></span>
<label>Softness <span id="ge-eraser-softness-label">100%</span></label>
<input type="range" id="ge-eraser-softness" min="0" max="300" value="100" title="Soft brush edge — blurs the stroke's alpha so the eraser fades out at the perimeter." />
</div>
</div>
<div class="ge-brush-stroke-group" data-stroke-tool="clone">
<div class="ge-section-title" id="ge-stroke-title-clone">Clone</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-clone-preview-opacity" aria-hidden="true"></span>
<label>Opacity <span id="ge-clone-opacity-label">100%</span></label>
<input type="range" id="ge-clone-opacity" min="10" max="100" value="100" />
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-clone-preview-flow" aria-hidden="true"></span>
<label>Flow <span id="ge-clone-flow-label">100%</span></label>
<input type="range" id="ge-clone-flow" min="5" max="100" value="100" />
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-clone-preview-softness" aria-hidden="true"></span>
<label>Softness <span id="ge-clone-softness-label">100%</span></label>
<input type="range" id="ge-clone-softness" min="0" max="300" value="100" title="Soft brush edge — blurs each stamp for a feathered fade." />
</div>
</div>
<div class="ge-brush-stroke-group" data-stroke-tool="smudge">
<div class="ge-section-title">Smudge</div>
<div class="ge-control-row ge-eraser-row" id="ge-smudge-strength-row">
<span class="ge-eraser-preview" id="ge-smudge-preview-strength" aria-hidden="true"></span>
<label>Strength <span id="ge-smudge-strength-label">65%</span></label>
<input type="range" id="ge-smudge-strength" min="5" max="100" value="65" title="How strongly Smudge carries sampled pixels into the stroke." />
</div>
</div>
<div class="ge-control-row ge-brush-pressure-row">
<span class="ge-pressure-option" title="Pen pressure changes flow"><span>Flow</span><label class="toggle-switch"><input type="checkbox" id="ge-pressure-flow" checked /><span class="toggle-slider"></span></label></span>
</div>
</div>
</span>
</div>
<div class="ge-section-title">Stroke</div >
<div class="ge-control-row ge-eraser-row" >
<label>Spacing <span id="ge-brush-spacing -label">1 5%</span></label>
<input type="range" id="ge-brush-spacing " min="1 " max="100" value="15 " />
</div>
<div class="ge-control-row ge-eraser-row">
<label>Smoothing <span id="ge-brush-smoothing-label">25%</span></label>
<input type="range" id="ge-brush-smoothing" min="0" max="95" value="25" />
</div>
<div class="ge-control-row">
<label for="ge-brush-blend">Blend</label>
<select id="ge-brush-blend">
<option value="source-over">Normal</option><option value="multiply">Multiply</option>
<option value="screen">Screen</option><option value="overlay">Overlay</option>
<option value="soft-light">Soft Light</option><option value="color">Color</option>
</select>
</div>
<div class="ge-control-row ge-brush-pressure-row">
<span class="ge-pressure-option" title="Pen pressure changes brush size"><span>Size</span><label class="toggle-switch"><input type="checkbox" id="ge-pressure-size" checked /><span class="toggle-slider"></span></label></span>
<span class="ge-pressure-option" title="Pen pressure changes opacity"><span>Opacity</span><label class="toggle-switch"><input type="checkbox" id="ge-pressure-opacity" /><span class="toggle-slider"></span></label></span>
<span class="ge-pressure-option" title="Pen pressure changes flow"><span>Flow</span><label class="toggle-switch"><input type="checkbox" id="ge-pressure-flow" checked /><span class="toggle-slider"></span></label></span>
<div class="ge-control-row ge-eraser-row" id="ge-dodgeburn-intensity-row" style="display:none;" >
<span class="ge-eraser-preview" id="ge-dodgeburn-preview" aria-hidden="true"></span >
<label title="Intensity">Int <span id="ge-dodgeburn-intensity -label">2 5%</span></label>
<input type="range" id="ge-dodgeburn-intensity " min="0 " max="100" value="25" title="How strongly Dodge lightens or Burn darkens each dab. " />
</div>
<div class="ge-control-row ge-brush-preset-row">
<select id="ge-brush-preset" aria-label="Brush preset"></select>
@@ -113,11 +209,14 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
<button type="button" class="ge-btn ge-btn-sm ge-crop-preset ${ cropAspectPreset === '1:1' ? ' active' : '' } " data-crop-preset="1:1" title="Square (1:1)">1:1</button>
<button type="button" class="ge-btn ge-btn-sm ge-crop-preset ${ cropAspectPreset === '4:5' ? ' active' : '' } " data-crop-preset="4:5" title="Portrait (4:5)">4:5</button>
<button type="button" class="ge-btn ge-btn-sm ge-crop-preset ${ cropAspectPreset === '16:9' ? ' active' : '' } " data-crop-preset="16:9" title="Widescreen (16:9)">16:9</button>
<label class="ge-crop-custom" title="Type any ratio, e.g. 3:2 or 21:9">
<input type="text" id="ge-crop-custom-ratio" inputmode="numeric" placeholder="W:H" aria-label="Custom crop ratio" spellcheck="false" autocomplete="off" />
</label>
</div>
<p class="ge-section-hint">Pick a ratio, then drag on the canvas. Press Enter to apply.</p>
</div>
<div class="ge-text-section" id="ge-text-section" style="display:none;">
<textarea id="ge-text-content" rows="3 " placeholder="Type text..." aria-label="Text content"></textarea>
<textarea id="ge-text-content" rows="2 " placeholder="Type text..." aria-label="Text content"></textarea>
<div class="ge-text-grid">
<label class="ge-text-field ge-text-font-field"><span>Font</span>
<select id="ge-text-font">
@@ -127,6 +226,11 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
<option value="Lobster">Lobster</option>
<option value="Bebas Neue">Bebas Neue</option>
<option value="Roboto Mono">Roboto Mono</option>
<option value="Space Grotesk">Space Grotesk</option>
<option value="Fraunces">Fraunces</option>
<option value="Syne">Syne</option>
<option value="Bungee">Bungee</option>
<option value="Instrument Serif">Instrument Serif</option>
<option value="Georgia">Georgia</option>
<option value="Courier New">Courier New</option>
</select>
@@ -144,6 +248,7 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
<button type="button" class="ge-text-toggle" data-text-align="center" title="Align center" aria-pressed="false">↔</button>
<button type="button" class="ge-text-toggle" data-text-align="right" title="Align right" aria-pressed="false">⇥</button>
</div>
<div class="ge-opt-more" id="ge-text-more" hidden>
<div class="ge-text-grid">
<label class="ge-text-field"><span>Line</span>
<input id="ge-text-line-height" type="number" min="0.5" max="5" step="0.1" value="1.2" />
@@ -200,6 +305,8 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
<label class="ge-text-field ge-text-inline-check"><span>Kerning</span><input type="checkbox" id="ge-text-kerning" checked /></label>
<label class="ge-text-field ge-text-inline-check"><span>Ligatures</span><input type="checkbox" id="ge-text-ligatures" checked /></label>
</div>
</div>
<button type="button" class="ge-btn ge-btn-sm ge-more-toggle" id="ge-text-more-toggle" aria-expanded="false" aria-controls="ge-text-more">More</button>
<button type="button" class="ge-btn ge-btn-sm" id="ge-text-rasterize">Rasterize</button>
</div>
<div class="ge-shape-section" id="ge-shape-section" style="display:none;">
@@ -214,6 +321,7 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
<label class="ge-text-field"><span>Fill</span><input type="color" class="ge-color-picker" id="ge-shape-fill" value=" ${ color } " /></label>
<label class="ge-text-field"><span>Stroke</span><input type="color" class="ge-color-picker" id="ge-shape-stroke" value="#111111" /></label>
</div>
<div class="ge-opt-more" id="ge-shape-more" hidden>
<div class="ge-text-grid">
<label class="ge-text-field"><span>Fill type</span>
<select id="ge-shape-fill-type"><option value="solid">Solid</option><option value="linear-gradient">Linear gradient</option></select>
@@ -234,6 +342,8 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
<label class="ge-text-field"><span>Radius</span><input id="ge-shape-radius" type="number" min="0" max="5000" step="1" value="0" /></label>
</div>
<label class="ge-text-field ge-shape-sides-field" hidden><span>Sides</span><input id="ge-shape-sides" type="number" min="3" max="24" step="1" value="5" /></label>
</div>
<button type="button" class="ge-btn ge-btn-sm ge-more-toggle" id="ge-shape-more-toggle" aria-expanded="false" aria-controls="ge-shape-more">More</button>
<button type="button" class="ge-btn ge-btn-sm" id="ge-shape-rasterize">Rasterize</button>
</div>
<div class="ge-path-section" id="ge-path-section" style="display:none;">
@@ -264,14 +374,13 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn active" data-wand-mode="replace" title="New selection">New</button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="add" title="Add to selection">+</button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="subtract" title="Subtract from selection">− </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="intersect" title="Intersect selection">∩ </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="intersect" title="Intersect selection"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" style="position:relative;top:2px"><circle cx="9" cy="12" r="6"/><circle cx="15" cy="12" r="6"/></svg> </button>
</div>
<div class="ge-marquee-constraint-row">
<label for="ge-marquee-constraint">Style</label>
<select id="ge-marquee-constraint" title="Marquee sizing style">
<option value="free">Free</option>
<option value="ratio">Fixed ratio</option>
<option value="size">Fixed size</option>
</select>
<div class="ge-marquee-dimensions" hidden>
<label>W <input type="number" id="ge-marquee-width" min="1" step="1" value="1" inputmode="decimal" /></label>
@@ -281,16 +390,18 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
</button>
</div>
</div>
<div class="ge-control-row ge-actions" style="margin-top:4 px;flex-wrap:wrap;">
<div class="ge-control-row ge-actions" style="margin-top:2 px;flex-wrap:wrap;">
<button class="ge-btn ge-btn-sm ge-mask-vis-btn visible" id="ge-marquee-vis" title="Hide selection overlay" aria-label="Toggle selection overlay">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel " id="ge-marquee-clear" title="Clear selection">Clear</butt on>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-marquee-invert" title="Invert selection">Invert</button >
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-marquee-delete" title="Erase selected pixels">Erase< /button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-marquee-copy " title="Copy selection to a new layer">Copy Lay er</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-marquee-mask" title="Add selection to mask">To M ask </button>
<button type="button" class="ge-btn ge-btn-sm ge-btn-iconlabel ge-quick-mask-toggle " title="Edit selection as Quick Mask (Q)" aria-pressed="false">Quick Mask </button>
<button class="ge-btn ge-btn-sm" id="ge-marquee-clear" title="Clear selection" aria-label="Clear selecti on" >
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg >
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-marquee-invert " title="Invert selection"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 1 0 18z" fill="currentColor" stroke="none"/></svg>Inv ert </button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-marquee-delete" title="Erase selected pixels"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 21-4-4a2 2 0 0 1 0-3l9-9a2 2 0 0 1 3 0l4 4a2 2 0 0 1 0 3l-9 9a2 2 0 0 1-3 0Z"/><path d="M22 21H7"/></svg>Er ase </button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-marquee-copy " title="Copy selection to a new layer"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>Copy Layer </button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-marquee-mask" title="Add selection to mask"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="12" cy="12" r="5"/></svg>To Mask</button>
<button type="button" class="ge-btn ge-btn-sm ge-btn-iconlabel ge-quick-mask-toggle" title="Edit selection as Quick Mask (Q)" aria-pressed="false"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" stroke-dasharray="3 3"/><circle cx="12" cy="12" r="3.5"/></svg>Quick Mask</button>
</div>
</div>
<div class="ge-lasso-section" id="ge-lasso-section" style="display:none;">
@@ -298,61 +409,62 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn active" data-wand-mode="replace" title="New selection">New</button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="add" title="Add to selection">+</button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="subtract" title="Subtract from selection">− </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="intersect" title="Intersect selection">∩ </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="intersect" title="Intersect selection"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" style="position:relative;top:2px"><circle cx="9" cy="12" r="6"/><circle cx="15" cy="12" r="6"/></svg> </button>
</div>
<div class="ge-control-row ge-eraser-row ge-sel-refine" id="ge-lasso-refine-feather" style="display:none; ">
<span class="ge-eraser-preview" id="ge-lasso-feather-preview" aria-hidden="true"></span >
<label>Feather <span id="ge-lasso-feather-label">0px</span></label >
<input type="range" id="ge-lasso-feather" min="0" max="200" value="0" title="Soften the selection edge — feathers the mask alpha." />
</div>
<div class="ge-control-row ge-eraser-row ge-sel-refine" id="ge-lasso-refine-grow" style="display:none;">
<span class="ge-eraser-preview" id="ge-lasso-grow-preview" aria-hidden="true"></span>
<label>Edge stroke <span id="ge-lasso-grow-label">0px</span></label>
<input type="range" id="ge-lasso-grow" min="-40" max="40" value="0" title="Expand (+) or contract (− ) the selection before baking." />
</div>
<div class="ge-control-row" style="margin-top:4px;">
<button type="button" class="ge-btn ge-btn-sm" id="ge-lasso-magnetic" aria-pressed="false" title="Snap the outline to image edges as you drag.">Magnetic</button>
</div>
<div class="ge-control-row ge-eraser-row" id="ge-lasso-mag-width-row" style="display:none;">
<label>Width <span id="ge-lasso-mag-width-label">12px</span></label>
<input type="range" id="ge-lasso-mag-width" min="2" max="60" value="12" title="Search radius for the strongest nearby edge." />
</div>
<div class="ge-control-row ge-eraser-row" id="ge-lasso-mag-contrast-row" style="display:none;">
<label>Contrast <span id="ge-lasso-mag-contrast-label">20%</span></label>
<input type="range" id="ge-lasso-mag-contrast" min="0" max="100" value="20" title="Minimum edge strength to snap to." />
</div>
<div class="ge-control-row ge-actions" style="margin-top:4px;flex-wrap:wrap;">
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-lasso-invert" title="Invert selection (Ctrl+Alt+Shift+I)">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg>
Invert
<span class="ge-lasso-more-wrap ">
<button type="button" class="ge-btn ge-btn-sm ge-lasso-more-btn" id="ge-lasso-more" aria-haspopup="true" aria-expanded="false" aria-label="More lasso options (feather, edge stroke, magnetic)" title="More lasso options (feather, edge stroke, magnetic)" >
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg >
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-lasso-delete" title="Delete selected pixels from the layer" >
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></svg >
Delete
<div class="ge-lasso-more-menu" id="ge-lasso-more-menu" hidden >
<div class="ge-control-row ge-eraser-row ge-sel-refine" id="ge-lasso-refine-feather" style="display:none;" >
<span class="ge-eraser-preview" id="ge-lasso-feather-preview" aria-hidden="true"></span>
<label>Feather <span id="ge-lasso-feather-label">0px</span></label>
<input type="range" id="ge-lasso-feather" min="0" max="200" value="0" title="Soften the selection edge — feathers the mask alpha." />
</div>
<div class="ge-control-row ge-eraser-row ge-sel-refine" id="ge-lasso-refine-grow" style="display:none;">
<span class="ge-eraser-preview" id="ge-lasso-grow-preview" aria-hidden="true"></span>
<label>Edge stroke <span id="ge-lasso-grow-label">0px</span></label>
<input type="range" id="ge-lasso-grow" min="-40" max="40" value="0" title="Expand (+) or contract (− ) the selection before baking." />
</div>
<div class="ge-control-row">
<button type="button" class="ge-btn ge-btn-sm" id="ge-lasso-magnetic" aria-pressed="false" title="Snap the outline to image edges as you drag.">Magnetic</button>
</div>
<div class="ge-control-row ge-eraser-row" id="ge-lasso-mag-width-row" style="display:none;">
<label>Width <span id="ge-lasso-mag-width-label">12px</span></label>
<input type="range" id="ge-lasso-mag-width" min="2" max="60" value="12" title="Search radius for the strongest nearby edge." />
</div>
<div class="ge-control-row ge-eraser-row" id="ge-lasso-mag-contrast-row" style="display:none;">
<label>Contrast <span id="ge-lasso-mag-contrast-label">20%</span></label>
<input type="range" id="ge-lasso-mag-contrast" min="0" max="100" value="20" title="Minimum edge strength to snap to." />
</div>
<p class="ge-lasso-tip">Draw a freehand selection. Esc to cancel.</p>
</div>
</span>
<div class="ge-control-row ge-actions" style="margin-top:2px;flex-wrap:wrap;">
<button class="ge-btn ge-btn-sm ge-mask-vis-btn visible" id="ge-lasso-vis" title="Hide selection overlay" aria-label="Toggle selection overlay">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel " id="ge-lasso-copy " title="Copy selection to new layer ">
<svg width="12 " height="12 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1 "/></svg>
Copy Layer
<button class="ge-btn ge-btn-sm" id="ge-lasso-clear " title="Clear selection" aria-label="Clear selection ">
<svg width="14 " height="14 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12 "/></svg>
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-lasso-mask " title="Co nvert selection to inpaint mask" >
<svg width="12 " height="12 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.06 11.9l8.07-8.06a2.85 2.85 0 1 1 4.03 4.03l-8.06 8.08"/><path d="M7.07 14.94c-1.66 0-3 1.35-3 3.02 0 1.33-2.5 1.52-2 2.02 1.08 1.1 2.49 2.02 4 2.02 2.2 0 4-1.8 4-4.04a3.01 3.01 0 0 0-3-3.02z"/></svg >
To Mask
</button>
<button type="button" class="ge-btn ge-btn-sm ge-btn-iconlabel ge-quick-mask-toggle" title="Edit selection as Quick Mask (Q)" aria-pressed="false">Quick Mask</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-lasso-invert " title="I nvert selection (Ctrl+Alt+Shift+I)"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 1 0 18z" fill="currentColor" stroke="none"/></svg>Invert</button >
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-lasso-delete" title="Erase selected pixels"> <svg width="14 " height="14 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 21-4-4a2 2 0 0 1 0-3l9-9a2 2 0 0 1 3 0l4 4a2 2 0 0 1 0 3l-9 9a2 2 0 0 1-3 0Z"/><path d="M22 21H7"/></svg>Erase</button >
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-lasso-copy" title="Copy selection to a new layer"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>Copy Layer</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-lasso-mask" title="Add selection to mask"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="12" cy="12" r="5"/></svg>To Mask< /button>
<button type="button" class="ge-btn ge-btn-sm ge-btn-iconlabel ge-quick-mask-toggle" title="Edit selection as Quick Mask (Q)" aria-pressed="false"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" stroke-dasharray="3 3"/><circle cx="12" cy="12" r="3.5"/></svg> Quick Mask</button>
</div>
<p style="font-size:9px;opacity:0.4;margin:4px 0 0;">Draw a freehand selection. Esc to cancel.</p>
</div>
<div class="ge-wand-section" id="ge-wand-section" style="display:none;">
<div class="ge-control-row" style="display:flex;gap:4px;margin-bottom:4px;" title="How the next click combines with the current selection. Shift / Alt held during a click override this for one click.">
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn active" data-wand-mode="replace" title="Replace selection on each click">New</button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="add" title="Add to selection (Shift)">+ Add </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="subtract" title="Subtract from selection (Alt)">− Subtract </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="intersect" title="Intersect selection">∩ </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="add" title="Add to selection (Shift)">+</button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="subtract" title="Subtract from selection (Alt)">− </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="intersect" title="Intersect selection"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" style="position:relative;top:2px"><circle cx="9" cy="12" r="6"/><circle cx="15" cy="12" r="6"/></svg> </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-live-btn" id="ge-wand-live" title="Retune selection while dragging tolerance" aria-pressed="false">Live</button>
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-wand-tol-preview" aria-hidden="true"></span>
<label>Tolerance <span id="ge-wand-tol-label"> ${ wandTolerance } </span></label>
<button type="button" class="ge-btn ge-btn-sm ge-wand-live-btn" id="ge-wand-live" title="Retune selection while dragging tolerance" aria-pressed="false">Live</button>
<input type="range" id="ge-wand-tolerance" min="0" max="100" value=" ${ wandTolerance } " />
</div>
<div class="ge-control-row ge-eraser-row ge-sel-refine" id="ge-wand-refine-feather" style="display:none;">
@@ -365,41 +477,38 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
<label>Edge stroke <span id="ge-wand-grow-label">0px</span></label>
<input type="range" id="ge-wand-grow" min="-40" max="40" value="0" title="Expand (+) or contract (− ) the selection before baking." />
</div>
<div class="ge-control-row ge-actions" style="margin-top:4 px;flex-wrap:wrap;">
<div class="ge-control-row ge-actions" style="margin-top:2 px;flex-wrap:wrap;">
<button class="ge-btn ge-btn-sm ge-mask-vis-btn visible" id="ge-wand-vis" title="Hide selection overlay" aria-label="Toggle selection overlay">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel " id="ge-wand-clear" title="Clear the selection">
<svg width="12 " height="12 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18 "/></svg>
Clear
<button class="ge-btn ge-btn-sm" id="ge-wand-clear" title="Clear selection" aria-label="Clear selection">
<svg width="14 " height="14 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18"/><path d="m6 6 12 12 "/></svg>
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-wand-invert" title="Invert selection (Ctrl+Alt+Shift+I)">
<svg width="12 " height="12 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 0 1-4 4H3 "/></svg>
<svg width="14 " height="14 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 1 0 18z" fill="currentColor" stroke="none "/></svg>
Invert
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-wand-delete" title="Delet e selected pixels from the layer ">
<svg width="12 " height="12 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18M8 6V 4a2 2 0 0 1 2-2h4 a2 2 0 0 1 2 2v2m3 0v1 4a2 2 0 0 1-2 2H7 a2 2 0 0 1-2-2V6 "/></svg>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-wand-delete" title="Eras e selected pixels">
<svg width="14 " height="14 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 21-4- 4a2 2 0 0 1 0-3l9-9 a2 2 0 0 1 3 0l4 4a2 2 0 0 1 0 3l-9 9 a2 2 0 0 1-3 0Z"/><path d="M22 21H7 "/></svg>
Erase
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-wand-copy" title="Copy selection to a new layer">
<svg width="12 " height="12 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13 " height="13 " rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
<svg width="14 " height="14 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="12 " height="12 " rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
Copy Layer
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-wand-mask" title="Add selection to the inpaint mask">
<svg width="12 " height="12 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.06 11.9l8.07-8.06a2.85 2.85 0 1 1 4.03 4.03l-8.06 8.08"/><path d="M7.07 14.94c-1.66 0-3 1.35-3 3.02 0 1.33-2.5 1.52-2 2.02 1.08 1.1 2.49 2.02 4 2.02 2.2 0 4-1.8 4-4.04a3.01 3.01 0 0 0-3-3.02z "/></svg>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-wand-mask" title="Add selection to mask">
<svg width="14 " height="14 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="12" cy="12" r="5 "/></svg>
To Mask
</button>
<button type="button" class="ge-btn ge-btn-sm ge-btn-iconlabel ge-quick-mask-toggle" title="Edit selection as Quick Mask (Q)" aria-pressed="false">Quick Mask</button>
<button type="button" class="ge-btn ge-btn-sm ge-btn-iconlabel ge-quick-mask-toggle" title="Edit selection as Quick Mask (Q)" aria-pressed="false"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" stroke-dasharray="3 3"/><circle cx="12" cy="12" r="3.5"/></svg> Quick Mask</button>
</div>
<p style="font-size:9px;opacity:0.4;margin:4px 0 0;">Click a region to select similar pixels. Shift+click to add, Alt+click to subtract. Esc to clear.</p>
</div>
<div class="ge-sam-section" id="ge-sam-section" style="display:none;">
<div class="ge-section-title ge-section-title-with-help"><span>SAM</span><span class="ge-section-help" tabindex="0" role="img" aria-label="SAM selection help" title="Click an object for visual SAM selection, or type a neutral object label and use Find. The text is only used to locate a region before SAM creates the mask.">?</span></div>
<div class="ge-control-row" style="display:flex;gap:4px;margin-bottom:4px;" title="How the next SAM selection combines with the current selection. Shift / Alt held during a click override this for one click.">
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn active" data-wand-mode="replace" title="Replace selection">New</button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="add" title="Add to selection">+ Add </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="subtract" title="Subtract from selection">− Subtract </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="intersect" title="Intersect selection">∩ </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="add" title="Add to selection">+</button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="subtract" title="Subtract from selection">− </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="intersect" title="Intersect selection"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" style="position:relative;top:2px"><circle cx="9" cy="12" r="6"/><circle cx="15" cy="12" r="6"/></svg> </button>
</div>
<div class="ge-control-row" style="display:flex;gap:6px;align-items:center;min-width:0;">
<input type="text" class="ge-inpaint-prompt" id="ge-sam-query" placeholder="Object to select..." style="flex:1 1 auto;min-width:0;" />
@@ -408,46 +517,120 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
Find
</button>
</div>
<div class="ge-control-row ge-actions" style="margin-top:4px;flex-wrap:wrap; ">
<span class="ge-wand-more-wrap ">
<button type="button" class="ge-btn ge-btn-sm ge-wand-more-btn" id="ge-sam-more" aria-haspopup="true" aria-expanded="false" aria-label="More SAM options (help)" title="More SAM options (help)"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></button>
<div class="ge-wand-more-menu" id="ge-sam-more-menu" hidden>
<p class="ge-wand-tip">Click an object for visual SAM selection, or type a neutral object label and use Find. The text is only used to locate a region before SAM creates the mask. Shift adds, Alt subtracts, Esc clears.</p>
</div>
</span>
<div class="ge-control-row ge-actions" style="margin-top:2px;flex-wrap:wrap;">
<button class="ge-btn ge-btn-sm ge-mask-vis-btn visible" id="ge-sam-vis" title="Hide selection overlay" aria-label="Toggle selection overlay">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel " id="ge-sam-clear" title="Clear the selection">
<svg width="12 " height="12 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18 "/></svg>
Clear
<button class="ge-btn ge-btn-sm" id="ge-sam-clear" title="Clear selection" aria-label="Clear selection">
<svg width="14 " height="14 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18"/><path d="m6 6 12 12 "/></svg>
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-sam-mask " title="Add selection to the inpaint mask ">
<svg width="12 " height="12 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.06 11.9l8.07-8.06a2.85 2.85 0 1 1 4.03 4.03l-8.06 8.08"/><path d="M7.07 14.94c-1.66 0-3 1.35-3 3.02 0 1.33-2.5 1.52-2 2.02 1.08 1.1 2.49 2.02 4 2.02 2.2 0 4-1.8 4-4.04a3.01 3.01 0 0 0-3-3.02z "/></svg>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-sam-invert " title="Invert selection (Ctrl+Alt+Shift+I) ">
<svg width="14 " height="14 " viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 1 0 18z" fill="currentColor" stroke="none "/></svg>
Invert
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-sam-delete" title="Erase selected pixels">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 21-4-4a2 2 0 0 1 0-3l9-9a2 2 0 0 1 3 0l4 4a2 2 0 0 1 0 3l-9 9a2 2 0 0 1-3 0Z"/><path d="M22 21H7"/></svg>
Erase
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-sam-copy" title="Copy selection to a new layer">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
Copy Layer
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-sam-mask" title="Add selection to mask">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="12" cy="12" r="5"/></svg>
To Mask
</button>
<button type="button" class="ge-btn ge-btn-sm ge-btn-iconlabel ge-quick-mask-toggle" title="Edit selection as Quick Mask (Q)" aria-pressed="false">Quick Mask</button>
<button type="button" class="ge-btn ge-btn-sm ge-btn-iconlabel ge-quick-mask-toggle" title="Edit selection as Quick Mask (Q)" aria-pressed="false"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" stroke-dasharray="3 3"/><circle cx="12" cy="12" r="3.5"/></svg> Quick Mask</button>
</div>
<p style="font-size:9px;opacity:0.4;margin:4px 0 0;">Click an object, or type a neutral object label. Shift adds, Alt subtracts.</p>
</div>
<div class="ge-quickselect-section" id="ge-quickselect-section" style="display:none;">
<div class="ge-section-title ge-section-title-with-help"><span>QUICK SELECT</span><span class="ge-section-help" tabindex="0" role="img" aria-label="Quick Select help" title="Brush over a region to grow the selection to similar nearby pixels. Shift adds, Alt subtracts, Shift+Alt intersects.">?</span></div>
<div class="ge-control-row" style="display:flex;gap:4px;margin-bottom:4px;" title="How the brush combines with the current selection. Shift / Alt held during a stroke override this.">
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn active" data-wand-mode="replace" title="Replace selection">New</button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="add" title="Add to selection">+ Add </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="subtract" title="Subtract from selection">− Subtract </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="intersect" title="Intersect selection">∩ </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="add" title="Add to selection">+</button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="subtract" title="Subtract from selection">− </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="intersect" title="Intersect selection"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" style="position:relative;top:2px"><circle cx="9" cy="12" r="6"/><circle cx="15" cy="12" r="6"/></svg> </button>
</div>
<div class="ge-control-row" style="display:flex;gap:6px;align-items:center;min-width:0; ">
<label style="font-size:10px;opacity:.7;white-space:nowrap;">Brush</label >
<input type="range" class="ge-quickselect-size" id="ge-quickselect-size" min="4" max="200" value="24" style="flex:1 1 auto;min-width:0;" / >
<span class="ge-adj-value" id="ge-quickselect-size-value">24</span >
<div class="ge-control-row ge-eraser-row ">
<span class="ge-eraser-preview" id="ge-quickselect-size-preview" aria-hidden="true"></span >
<label>Brush <span id="ge-quickselect-size-label">24</span></label >
<input type="range" class="ge-quickselect-size" id="ge-quickselect-size" min="4" max="200" value="24" / >
</div>
<span class="ge-wand-more-wrap">
<button type="button" class="ge-btn ge-btn-sm ge-wand-more-btn" id="ge-quickselect-more" aria-haspopup="true" aria-expanded="false" aria-label="More Quick Select options (help)" title="More Quick Select options (help)"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></button>
<div class="ge-wand-more-menu" id="ge-quickselect-more-menu" hidden>
<p class="ge-wand-tip">Paint over a region; the brush grows the selection to similar nearby pixels. Shift adds, Alt subtracts, Shift+Alt intersects.</p>
</div>
</span>
<div class="ge-control-row ge-actions" style="margin-top:2px;flex-wrap:wrap;">
<button class="ge-btn ge-btn-sm ge-mask-vis-btn visible" id="ge-quickselect-vis" title="Hide selection overlay" aria-label="Toggle selection overlay">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
<button class="ge-btn ge-btn-sm" id="ge-quickselect-clear" title="Clear selection" aria-label="Clear selection">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-quickselect-invert" title="Invert selection (Ctrl+Alt+Shift+I)">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 1 0 18z" fill="currentColor" stroke="none"/></svg>
Invert
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-quickselect-delete" title="Erase selected pixels">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 21-4-4a2 2 0 0 1 0-3l9-9a2 2 0 0 1 3 0l4 4a2 2 0 0 1 0 3l-9 9a2 2 0 0 1-3 0Z"/><path d="M22 21H7"/></svg>
Erase
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-quickselect-copy" title="Copy selection to a new layer">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
Copy Layer
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-quickselect-mask" title="Add selection to mask">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="12" cy="12" r="5"/></svg>
To Mask
</button>
<button type="button" class="ge-btn ge-btn-sm ge-btn-iconlabel ge-quick-mask-toggle" title="Edit selection as Quick Mask (Q)" aria-pressed="false"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" stroke-dasharray="3 3"/><circle cx="12" cy="12" r="3.5"/></svg>Quick Mask</button>
</div>
<p style="font-size:9px;opacity:0.4;margin:4px 0 0;">Paint over a region; the brush grows the selection to similar nearby pixels.</p>
</div>
<div class="ge-objectselect-section" id="ge-objectselect-section" style="display:none;">
<div class="ge-section-title ge-section-title-with-help"><span>OBJECT SELECT</span><span class="ge-section-help" tabindex="0" role="img" aria-label="Object Select help" title="Draw over an object; the SAM model selects the whole object. Hold Alt to mark pixels to exclude.">?</span></div>
<div class="ge-control-row" style="display:flex;gap:4px;margin-bottom:4px;" title="How the object selection combines with the current selection. Shift / Alt held during a stroke override this.">
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn active" data-wand-mode="replace" title="Replace selection">New</button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="add" title="Add to selection">+ Add </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="subtract" title="Subtract from selection">− Subtract </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="intersect" title="Intersect selection">∩ </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="add" title="Add to selection">+</button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="subtract" title="Subtract from selection">− </button>
<button type="button" class="ge-btn ge-btn-sm ge-wand-mode-btn" data-wand-mode="intersect" title="Intersect selection"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" style="position:relative;top:2px"><circle cx="9" cy="12" r="6"/><circle cx="15" cy="12" r="6"/></svg> </button>
</div>
<span class="ge-wand-more-wrap">
<button type="button" class="ge-btn ge-btn-sm ge-wand-more-btn" id="ge-objectselect-more" aria-haspopup="true" aria-expanded="false" aria-label="More Object Select options (help)" title="More Object Select options (help)"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></button>
<div class="ge-wand-more-menu" id="ge-objectselect-more-menu" hidden>
<p class="ge-wand-tip">Draw over an object; the SAM model selects the whole object. Hold Alt to mark pixels to exclude. Shift adds, Esc clears.</p>
</div>
</span>
<div class="ge-control-row ge-actions" style="margin-top:2px;flex-wrap:wrap;">
<button class="ge-btn ge-btn-sm ge-mask-vis-btn visible" id="ge-objectselect-vis" title="Hide selection overlay" aria-label="Toggle selection overlay">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
<button class="ge-btn ge-btn-sm" id="ge-objectselect-clear" title="Clear selection" aria-label="Clear selection">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-objectselect-invert" title="Invert selection (Ctrl+Alt+Shift+I)">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 1 0 18z" fill="currentColor" stroke="none"/></svg>
Invert
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-objectselect-delete" title="Erase selected pixels">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 21-4-4a2 2 0 0 1 0-3l9-9a2 2 0 0 1 3 0l4 4a2 2 0 0 1 0 3l-9 9a2 2 0 0 1-3 0Z"/><path d="M22 21H7"/></svg>
Erase
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-objectselect-copy" title="Copy selection to a new layer">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
Copy Layer
</button>
<button class="ge-btn ge-btn-sm ge-btn-iconlabel" id="ge-objectselect-mask" title="Add selection to mask">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="12" cy="12" r="5"/></svg>
To Mask
</button>
<button type="button" class="ge-btn ge-btn-sm ge-btn-iconlabel ge-quick-mask-toggle" title="Edit selection as Quick Mask (Q)" aria-pressed="false"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" stroke-dasharray="3 3"/><circle cx="12" cy="12" r="3.5"/></svg>Quick Mask</button>
</div>
<p style="font-size:9px;opacity:0.4;margin:4px 0 0;">Draw a rough stroke over an object; SAM selects its boundary.</p>
</div>
<div class="ge-inpaint-section" id="ge-inpaint-section" style="display:none;">
<div class="ge-inpaint-popover-head" data-inpaint-drag>
@@ -550,72 +733,19 @@ export function controlsHTML({ color, brushSize, wandTolerance, bucketTolerance
</p>
<div class="ge-clone-source-status" id="ge-clone-source-status" aria-live="polite">
<span id="ge-clone-source-label">No source selected</span>
<button type="button" class="ge-btn ge-btn-sm ge-icon-btn " id="ge-clone-source-clear" title="Clear sampled source" aria-label="Clear sampled source">× </button>
<button type="button" class="ge-btn ge-btn-sm" id="ge-clone-source-clear" title="Clear sampled source" aria-label="Clear sampled source">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg>
</button>
</div>
<div class="ge-control-row">
<label for="ge-clone-sample-mode">Sample</label>
<select id="ge-clone-sample-mode">
<select id="ge-clone-sample-mode" class="ge-ctl-select" >
<option value="active-layer">Active layer</option>
<option value="composite">All visible layers</option>
</select>
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-clone-preview-opacity" aria-hidden="true"></span>
<label>Opacity <span id="ge-clone-opacity-label">100%</span></label>
<input type="range" id="ge-clone-opacity" min="10" max="100" value="100" />
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-clone-preview-flow" aria-hidden="true"></span>
<label>Flow <span id="ge-clone-flow-label">100%</span></label>
<input type="range" id="ge-clone-flow" min="5" max="100" value="100" />
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-clone-preview-softness" aria-hidden="true"></span>
<label>Softness <span id="ge-clone-softness-label">100%</span></label>
<input type="range" id="ge-clone-softness" min="0" max="300" value="100" title="Soft brush edge — blurs each stamp for a feathered fade." />
</div>
</div>
<div class="ge-eraser-section" id="ge-brush-section" style="display:none;">
<div class="ge-section-title"><span>Brush</span></div>
<div class="ge-control-row ge-eraser-row" id="ge-smudge-strength-row" style="display:none;">
<span class="ge-eraser-preview" id="ge-smudge-preview-strength" aria-hidden="true"></span>
<label>Strength <span id="ge-smudge-strength-label">65%</span></label>
<input type="range" id="ge-smudge-strength" min="5" max="100" value="65" title="How strongly Smudge carries sampled pixels into the stroke." />
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-brush-preview-opacity" aria-hidden="true"></span>
<label>Opacity <span id="ge-brush-opacity-label">100%</span></label>
<input type="range" id="ge-brush-opacity" min="10" max="100" value="100" />
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-brush-preview-flow" aria-hidden="true"></span>
<label>Flow <span id="ge-brush-flow-label">100%</span></label>
<input type="range" id="ge-brush-flow" min="5" max="100" value="100" />
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-brush-preview-softness" aria-hidden="true"></span>
<label>Softness <span id="ge-brush-softness-label">100%</span></label>
<input type="range" id="ge-brush-softness" min="0" max="300" value="100" title="Soft brush edge — blurs the stroke's alpha for a feathered fade at the perimeter." />
</div>
</div>
<div class="ge-eraser-section" id="ge-eraser-section" style="display:none;">
<div class="ge-section-title">Eraser</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-eraser-preview-opacity" aria-hidden="true"></span>
<label>Opacity <span id="ge-eraser-opacity-label">100%</span></label>
<input type="range" id="ge-eraser-opacity" min="10" max="100" value="100" />
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-eraser-preview-flow" aria-hidden="true"></span>
<label>Flow <span id="ge-eraser-flow-label">100%</span></label>
<input type="range" id="ge-eraser-flow" min="5" max="100" value="100" />
</div>
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-eraser-preview-softness" aria-hidden="true"></span>
<label>Softness <span id="ge-eraser-softness-label">100%</span></label>
<input type="range" id="ge-eraser-softness" min="0" max="300" value="100" title="Soft brush edge — blurs the stroke's alpha so the eraser fades out at the perimeter." />
</div>
</div>
<div class="ge-transform-section" id="ge-transform-section" style="display:none;"></div>
<div class="ge-sharpen-section" id="ge-sharpen-section" style="display:none;">
<div class="ge-control-row ge-eraser-row">
<span class="ge-eraser-preview" id="ge-sharpen-preview" aria-hidden="true"></span>