diff --git a/cmd/ninja/cmd/theme.go b/cmd/ninja/cmd/theme.go index e1e143c..1b8b0e7 100644 --- a/cmd/ninja/cmd/theme.go +++ b/cmd/ninja/cmd/theme.go @@ -26,6 +26,7 @@ func newThemeScreenshotCmd() *cobra.Command { var pages, screenshotsDir, modes string var mobile bool var width, height int + var scale float64 cmd := &cobra.Command{ Use: "screenshot", Short: "Render this theme's showcase page and write preview.png into the repo", @@ -68,6 +69,7 @@ the rest of the CLI.`, Height: height, WaitSelector: waitSelector, Timeout: 45 * time.Second, + Scale: scale, }) if err != nil { return err @@ -86,6 +88,7 @@ the rest of the CLI.`, Height: 844, WaitSelector: waitSelector, Timeout: 45 * time.Second, + Scale: scale, }) if err != nil { return err @@ -124,6 +127,7 @@ the rest of the CLI.`, WaitSelector: waitSelector, Timeout: 45 * time.Second, Mode: mode, + Scale: scale, }) if err != nil { return err @@ -155,6 +159,7 @@ the rest of the CLI.`, cmd.Flags().IntVar(&height, "height", 900, "Desktop viewport height") cmd.Flags().StringVar(&pages, "pages", "", "Comma-separated page slugs to capture into --screenshots-dir (e.g. /,/blog,/about)") cmd.Flags().StringVar(&screenshotsDir, "screenshots-dir", "screenshots", "Directory for --pages captures (packed into the .bnp)") + cmd.Flags().Float64Var(&scale, "scale", 1, "Device scale factor (2 = retina PNGs at Width*2 x Height*2)") cmd.Flags().StringVar(&modes, "modes", "", `Comma-separated color modes for --pages captures: "light", "dark" or "light,dark" (sets the bn-theme cookie per capture; empty = site default, unsuffixed filenames)`) return cmd } diff --git a/internal/shot/shot.go b/internal/shot/shot.go index 1d01b6d..0f4739b 100644 --- a/internal/shot/shot.go +++ b/internal/shot/shot.go @@ -25,6 +25,7 @@ type Options struct { WaitSelector string // CSS selector to wait for before capturing (e.g. "section") Timeout time.Duration // overall navigation+capture timeout Mode string // "" (site default), "light" or "dark" — sets the bn-theme cookie + emulated prefers-color-scheme before navigation + Scale float64 // device scale factor; 0 = 1.0. 2 captures retina PNGs (Width*2 × Height*2 px) } // PreviewURL composes the gallery-page URL with the render-only override. @@ -68,8 +69,12 @@ func Capture(ctx context.Context, opts Options) ([]byte, error) { defer cancelTimeout() var buf []byte + viewport := []chromedp.EmulateViewportOption(nil) + if opts.Scale > 0 { + viewport = append(viewport, chromedp.EmulateScale(opts.Scale)) + } tasks := chromedp.Tasks{ - chromedp.EmulateViewport(int64(opts.Width), int64(opts.Height)), + chromedp.EmulateViewport(int64(opts.Width), int64(opts.Height), viewport...), } if opts.Mode == "light" || opts.Mode == "dark" { u, err := url.Parse(opts.URL)