tungs / timesnap

Node.js program that takes screenshots at smooth intervals of web pages with JavaScript animations
BSD 3-Clause "New" or "Revised" License
234 stars 57 forks source link

[BUG] three.js scene wont render on page with overwritten time #77

Open yoavniran opened 1 year ago

yoavniran commented 1 year ago

Describe the bug First of all, thanks for a very cool library.

I have a page with a canvas id like to record. the page works fine in the browser and in headless. Its already being used to take snapshots with a custom set up of puppeteer.

The canvas is showing a three.js 3d model using react-three-fiber.

Im trying to use timecut but of course most of the set up is done with timesnap. When I run my code without Timecut/snap, I get my promise resolved from the evaluate:


await page
        .evaluate(
            async (config) => {             
                console.log("CALLING INIT SCENE ON PAGE !", config);
                const initRes = await initScene(config);
                console.log("PAGE RETURNED FROM INIT !!! ");                
            }, config);

code above is simplified. initScene is a globally available function on my page

this resolves fine without a page that had its time overwritten. For a page that comes from timsnap, this never completes.

I have console.log inside the code that runs on my page. Those are never reached for the timesnap-ed page. While if I create the page from puppeteer directly, they all run and the promise is resolved.

I dont know what overwriting the time/random actually does but it seems to be interfering with the rendering of the three.js scene.

The problem is that these lines in timesnap

   await overwriteRandom(page, unrandom, log);
    await timeHandler.overwriteTime(page);

are called before navigatePageToURL and preparePage. If I was able to do my scene initialization before the overwriting, perhaps it would have worked.

there are no errors coming from the page itself. I used the page.on("console"... way to get all of the console messages from the page and there's nothing that is printed that suggests something in the JS code broke...

To Reproduce

unfortunately, the code for the environment to take the screenshots and the actual rendering page (loaded into puppeteer) are property of my workplace so re-creating a full replica without the propriety stuff will be a lot of work.

Im hoping to see Im missing something or perhaps someone else encountered this issue and has insight. Thanks.

This is the timecut/snap code im running:


const BROWSER_ARGS = ["--no-sandbox"];

const getBrowser = async (options = {}) => {
    return await puppeteer.launch({
        ...options,
        headless: "new",
        ignoreHTTPSErrors: true,
        args: BROWSER_ARGS,
    });
};

const loadRendererPage = async (page, url, ) => {
    await page.goto(url, { waitUntil: "domcontentloaded" });
    console.log("RENDERER PAGE DOM WAS LOADED");
};

const initRenderer = async (page) => {
    const renderOptions = {
        model: {
            url: "my-3d-model"
        },
    };

    let timeoutHandle = setTimeout(() => {
        console.error("PREPARE PAGE TIMED OUT !!! closing browser");
        page.browser().close();
    }, PREPARE_TIMEOUT);

    const pageInitResult = await page
        .evaluate(
            async (renderOptions) => {
                const config = {
                    ...renderOptions,
                };

                console.log("CALLING INIT ON PAGE !", config);
                const initRes = await initVideo(config);
                console.log("PAGE RETURNED FROM INIT !!! ");
                return initRes;
            }, renderOptions);

    if (timeoutHandle) {
        clearTimeout(timeoutHandle);
        timeoutHandle = null;
    }

    console.log("preparePage ----> returning to controller ", pageInitResult
};

const renderWithTimecut = async () => {
        timecut({
            quiet: false,
            url: RENDERER_URL,
            viewport: {
                width: 1200,               
                height: 900,
            },
            selector: ".App canvas",    
            fps: 60,                  
            duration: 5,        
            output: FILE_NAME,      

            launcher: (launchOptions) => {
                return  await getBrowser(launchOptions);                
            },

            canvasCaptureMode: "immediate:png",
            pipeMode: true,
            inputOptions: FFMPEG_OPTIONS,

            navigatePageToURL: async ({ page, url, log }) => {
                await loadRendererPage(page, url);
                await initRenderer(page);
                log("Navigation Complete - ", url);
            },
        })

Expected behavior I dont know if this is a general issue with timesnap and three.js or with react-three-fiber (also using drei). But I expect the page I want to screenshot to load correctly.

Desktop (please complete the following information):