{"record":{"id":"6c584e6a6640beb8","repo":"garrytan/gstack","slug":"usage-browse-viewport-wxh-scale-n-e-g-6c584e","errorCode":null,"errorMessage":"Usage: browse viewport [<WxH>] [--scale <n>] (e.g., 375x812)","messagePattern":"Usage: browse viewport \\[<WxH>\\] \\[--scale <n>\\] \\(e\\.g\\., 375x812\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"browse/src/write-commands.ts","lineNumber":532,"sourceCode":"          }\n          scaleArg = parsed;\n        } else if (args[i].startsWith('--')) {\n          throw new Error(`Unknown viewport flag: ${args[i]}`);\n        } else if (sizeArg === undefined) {\n          sizeArg = args[i];\n        } else {\n          throw new Error(`Unexpected positional arg: ${args[i]}. Usage: viewport [WxH] [--scale <n>]`);\n        }\n      }\n\n      if (sizeArg === undefined && scaleArg === undefined) {\n        throw new Error('Usage: browse viewport [<WxH>] [--scale <n>]  (e.g. 375x812, or --scale 2 to keep current size)');\n      }\n\n      // Resolve width/height: either from sizeArg or from current viewport if --scale-only.\n      let w: number, h: number;\n      if (sizeArg) {\n        if (!sizeArg.includes('x')) throw new Error('Usage: browse viewport [<WxH>] [--scale <n>] (e.g., 375x812)');\n        const [rawW, rawH] = sizeArg.split('x').map(Number);\n        w = Math.min(Math.max(Math.round(rawW) || 1280, 1), 16384);\n        h = Math.min(Math.max(Math.round(rawH) || 720, 1), 16384);\n      } else {\n        // --scale without WxH → use BrowserManager's tracked viewport (source of truth\n        // since setViewport + launchContext keep it in sync). Falls back reliably on\n        // headed → headless transitions or contexts with viewport:null.\n        const current = bm.getCurrentViewport();\n        w = current.width;\n        h = current.height;\n      }\n\n      if (scaleArg !== undefined) {\n        const err = await bm.setDeviceScaleFactor(scaleArg, w, h);\n        if (err) return `Viewport partially set: ${err}`;\n        return `Viewport set to ${w}x${h} @ ${scaleArg}x (context recreated; refs and load-html content replayed)`;\n      }\n","sourceCodeStart":514,"sourceCodeEnd":550,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/write-commands.ts#L514-L550","documentation":"Thrown by `browse viewport` when a size argument IS supplied but does not contain the `x` width×height separator. The parser reaches the size-resolution block, calls `sizeArg.includes('x')`, and on `false` rejects the value because it cannot split it into width and height. The accepted form is `<W>x<H>` such as `375x812`.","triggerScenarios":"Passing `browse viewport 375X812` (capital X), `browse viewport 375*812`, `browse viewport 1080` (single dimension), `browse viewport 375,812`, or `browse viewport 375x` (trailing x with no height, which `split('x').map(Number)` would yield NaN for and is better rejected explicitly).","commonSituations":"User copies a resolution from a spec written as `375 × 812` or `375*812`; an agent emits dimensions using the wrong separator it inferred from the page; locale-specific number formatting where a user tries `1080x1920` but a smart-quote or non-ASCII `x` (U+00D7 multiply sign) slips in.","solutions":["Use a lowercase `x` with no surrounding spaces: `browse viewport 375x812`.","If you copied the value, re-type the separator manually to avoid smart quotes or U+00D7.","Provide both dimensions; the command does not accept a single dimension.","If you meant to scale rather than resize, switch to `browse viewport --scale <n>`."],"exampleFix":"// before\nawait runBrowseCommand(['viewport', '375X812']);\n\n// after\nawait runBrowseCommand(['viewport', '375x812']);","handlingStrategy":"validation","validationCode":"function parseViewportSize(arg: string): { w: number; h: number } {\n  const m = /^(\\d+)x(\\d+)$/i.exec(arg.trim());\n  if (!m) throw new Error(`Expected <W>x<H> (e.g. 375x812), got: ${arg}`);\n  return { w: Number(m[1]), h: Number(m[2]) };\n}","typeGuard":"function isViewportSizeToken(s: string): boolean {\n  return /^\\d+x\\d+$/i.test(s);\n}","tryCatchPattern":null,"preventionTips":["Use a lowercase ASCII 'x' as the width/height separator.","Re-type the separator when copy-pasting resolutions to avoid smart quotes or U+00D7.","Provide both dimensions; single-dimension forms are unsupported."],"tags":["cli-usage","viewport","argument-parsing","browse-command"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}