question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Render function called twice while exporting

See original GitHub issue

I noticed while experimenting with canvas-sketch that when you export an image using <kbd>cmd</kbd> + <kbd>s</kbd> or an animation using <kbd>cmd</kbd> + <kbd>shift</kbd> + <kbd>s</kbd>, the render function is called twice for each frame.

To reproduce:

// bug-demo.js
const SKETCH = require('canvas-sketch')

const sketch = () => {
  return ({ frame }) => {
    console.log(`render frame ${frame}`)
  }
}

SKETCH(sketch)

Then launch:

canvas-sketch bug-demo.js --open

Open the browser console and then try saving with <kbd>cmd</kbd> + <kbd>s</kbd> and you should see “render frame 0” logged twice.

Here are the relevant lines from my console (Firefox 62.0.3):

browser console output demonstrating error

“render frame 0” is logged once on page load, then twice more on export/save. When exporting an animation the duplication happens for each frame.

I imagine this has performance implications, but I also tripped up on it because I was using a generator function to get the next value to display for each frame. Each frame was being rendered twice (and saved once), which meant every other value returned from the generator was lost.


P.S. Generally the experience getting started with this has been really great. Thanks for the thoughtful library and clear documentation!

Issue Analytics

  • State:open
  • Created 5 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
mattdeslcommented, Oct 26, 2018

Thanks for the issue report! This is actually intentional, and not a bug. I’ll explain why:

In many sketches the visible size on screen (within your browser) will not match the export size. For example, if you are using { scaleToView: true } it allows you to export huge print sizes without rendering such massive canvases to the browser each frame. In these cases, upon Cmd + S, we have to render the canvas to the full export size, then capture its data URL, and then resize and re-render it back down to its original browser size to avoid an ugly “flash” of large canvas in the browser, and to ensure the user continues to see the scaled canvas in the browser.

Another situation is with { exporting } prop — sometimes you have a sketch where a certain feature should only be used during export (like ignoring debug rendering that you just want during a browser experience). In this case, we render twice: the first render says “this frame is being exported” and the second says “this frame is not being exported, but instead just visualized in the browser.” This way there is no flash of content while looking at the browser.

Just like with other declarative frameworks (React, Vue, etc) you should try not to assume too much about when the render() function will be called, as it may also get called in other situations such as on resize. Instead of creating side-effects in your render function, you should try to make it a pure function, such as by operating on the { frame } prop instead of increasing state on each render.

I’d also be happy to explore other solutions, if you let me know a bit more about why you needed to use a generator function. Maybe there is some syntax or documentation I could improve in canvas-sketch.

Cheers!

0reactions
mattdeslcommented, Nov 25, 2018

Does begin replace tick or render for the first frame, or supplement them? So far in my project I just implemented the render function, not any of these other lifecycle possibilities. Some are no longer relevant when rendering straight to video — e.g. the distinction between tick and render — but begin and end do seem potentially helpful.

begin and end can be used alongside tick and render. These things are still experimental but here is my plan so far:

  • begin is called at the start of playback, and also the beginning of each subsequent loop (so you can, for example, randomize parameters on each loop of an animation)
  • end is called after rendering the final frame, i.e. at the end of each loop (or never called if there is no finite duration to the animation)
  • tick is called before each frame, and before rendering each frame. Allows you to step physics and logic and move your animation forward.
  • render is called after tick in the animation loop, but also after the canvas is resized (i.e. by browser resize) and again just before the export (as the { exporting } prop has changed).

The second canvas is a cool idea but doing it automatically under the hood is just too magical for my taste, and could introduce a lot of new problems. I think its best that { canvas, context } props point to the same element that is visible in the DOM.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why does the render function in react is called twice when ...
I am new to react and what to understand why the console.log is called twice when inside of the render function ?
Read more >
ReactDOM – React
render () controls the contents of the container node you pass in. Any existing DOM elements inside are replaced when first called. Later...
Read more >
Why the React Component Renders Twice - Deni Apps
StrictMode, which could cause double rendering in the development mode. ... This method is not called for the initial render.
Read more >
React 18 - Avoiding Use Effect Getting Called Twice
How it works in a nutshell, I observed in React 18, if the effect runs, and then gets destroyed again before it renders,...
Read more >
React JS componentDidMount() Methods and Functional ...
componentDidMount() only runs once after the first render. componentDidMount() may be called multiple times if the key prop value for the ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found