From 098a2091b9ff8e1faa8b4251b15e37361d1389ca Mon Sep 17 00:00:00 2001 From: Alex Dunmow Date: Mon, 6 Jul 2026 10:23:43 +0800 Subject: [PATCH] feat(theme): --settle capture delay for reveal transitions and canvas heroes Scroll-reveal themes (gotham .reveal, scifi-clean data-sc-reveal) start content at opacity:0 under JS and fade in ~0.5s after the observer fires; capturing on WaitVisible(main) catches mid-transition ghosts. --settle adds a post-wait delay so transitions and canvas animations (cyberpunk rain) finish before the screenshot. Co-Authored-By: Claude Fable 5 --- cmd/ninja/cmd/theme.go | 5 +++++ internal/shot/shot.go | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/cmd/ninja/cmd/theme.go b/cmd/ninja/cmd/theme.go index 1b8b0e7..437c67f 100644 --- a/cmd/ninja/cmd/theme.go +++ b/cmd/ninja/cmd/theme.go @@ -27,6 +27,7 @@ func newThemeScreenshotCmd() *cobra.Command { var mobile bool var width, height int var scale float64 + var settle time.Duration cmd := &cobra.Command{ Use: "screenshot", Short: "Render this theme's showcase page and write preview.png into the repo", @@ -70,6 +71,7 @@ the rest of the CLI.`, WaitSelector: waitSelector, Timeout: 45 * time.Second, Scale: scale, + Settle: settle, }) if err != nil { return err @@ -89,6 +91,7 @@ the rest of the CLI.`, WaitSelector: waitSelector, Timeout: 45 * time.Second, Scale: scale, + Settle: settle, }) if err != nil { return err @@ -128,6 +131,7 @@ the rest of the CLI.`, Timeout: 45 * time.Second, Mode: mode, Scale: scale, + Settle: settle, }) if err != nil { return err @@ -159,6 +163,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().DurationVar(&settle, "settle", 0, "Extra wait after --wait matches before capturing (e.g. 1500ms; lets reveal transitions and canvas animations finish)") 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 0f4739b..fbf5116 100644 --- a/internal/shot/shot.go +++ b/internal/shot/shot.go @@ -26,6 +26,7 @@ type Options struct { 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) + Settle time.Duration // extra wait after WaitSelector before capturing — lets scroll-reveal transitions and canvas animations finish (0 = capture immediately) } // PreviewURL composes the gallery-page URL with the render-only override. @@ -99,6 +100,9 @@ func Capture(ctx context.Context, opts Options) ([]byte, error) { } else { tasks = append(tasks, chromedp.WaitReady("body", chromedp.ByQuery)) } + if opts.Settle > 0 { + tasks = append(tasks, chromedp.Sleep(opts.Settle)) + } if opts.FullPage { tasks = append(tasks, chromedp.FullScreenshot(&buf, 90)) } else {