I use Atom Editor. I want to make 20 seconds GIF with my canvas.
saveFrames() has a limitation(I guess). It enables to save .png files to short gifs(3-5 seconds), even if I type saveFrames("aa","png",15,22);
I discovered CCapture.js but I could not find any code example to export canvas.
It does not have to be exported as GIF; but I want to at least save .png snaps of
my animation in canvas limitlessly. How can I do it?
My animation code in p5.js:
var x = 0;
var speed = 10;
var d1 = 100;
var d2 = 100;
function setup() {
createCanvas(600, 400);
background(0);
//saveFrames("aa","png",15,22);
}
function draw() {
stroke(random(100, 255), 0, random(100, 190));
strokeWeight(1.5);
ellipse(x, 100, d1, d1);
x = x + speed;
d1 = d1 - 0.6;
if (x > width || x < 0) {
speed = speed * -1;
fill(speed * 51);
}
ellipse(x, 300, d1, d1);
ellipse(x, 200, 50, 50);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.1/p5.min.js"></script>
I've been working on a new library which supports GIF exports, p5.createLoop.
This will run the sketch and then render a GIF at the same frame rate.
function setup() {
createCanvas(600, 400);
background(0);
frameRate(22)
createLoop({duration:15,gif:true})
}
Here's a codePen with the full example. It'll take about two minutes and is over 50MB, totally worth it
After a full day of research, surprizingly, I found a video uploaded youtube 2 weeks ago:
CCapture Video
Dont forget that CCapture exports (gif size=canvas sizex2).
>= 1.5.0
P5 has saveGif as of 1.5.0, which lets you write n seconds or frames to a downloadable gif. See the docs for usage.
< 1.5.0
I want to at least save .png snaps of my animation in canvas limitlessly. How can I do it?
You can do this directly in p5.js using save(`${name}.png`) after each frame you want to snap. This normally pops a dialog prompt asking you where you want to save the file, but you can disable this in browsers (as of 2021) so the images get automatically sent to the default download location.
For example, in Chrome (Version 92.0.4515.159 at the time of writing this post), navigate to chrome://settings/downloads and disable "Ask where to save each file before downloading":
With the prompt disabled, I found that p5.js's default framerate was too high for the browser to keep up with the downloads, so I added frameRate(4); to setup so that only 4 frames run per second. You can speed this up a bit depending on your needs and compute power, but some throttling helped give me a clean, sequential download of each of the frames into separate PNGs.
Clearly, this procedure isn't at all user-friendly (or particularly elegant). It's intended for turning your sketches into gifs yourself rather than an interface feature of a public-facing website. That said, the process does open up ideas for interactivity using buttons and other triggers for controlling the next frame to export in a creative way. You could use a button to start/stop the animation, for example, or programmatically determine specific conditions to emit the next frame.
Here's the two relevant lines added to your sketch. You'll want to run this locally rather than as a Stack snippet, which runs in a sandboxed frame that won't have download access:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js">
</script>
</head>
<body>
<script>
var x = 0;
var speed = 10;
var d1 = 100;
var d2 = 100;
function setup() {
createCanvas(600, 400);
background(0);
frameRate(4); // <-- feel free to adjust
}
function draw() {
stroke(random(100, 255), 0, random(100, 190));
strokeWeight(1.5);
ellipse(x, 100, d1, d1);
x = x + speed;
d1 = d1 - 0.6;
if (x > width || x < 0) {
speed = speed * -1;
fill(speed * 51);
}
ellipse(x, 300, d1, d1);
ellipse(x, 200, 50, 50);
save(`frame_${frameCount}.png`); // <--
}
</script>
</body>
</html>
Once you have the frames downloaded, you can use your favorite PNG -> GIF creator. I used ffmpeg as described here: ffmpeg -f image2 -framerate 60 -i frame_%d.png -loop 0 out.gif.
Here's the result on the first few frames of your sketch (scaled down 50% with ffmpeg's -vf scale=300x200 flag to keep bandwidth for this page reasonable):
Related
I am VERY new to P5.js/processing (taking programming for artists). I am trying to make a crude game where an image (Jar Jar) bounces across the screen and another image (lightsaber) that moves with the mouse and when the mouse attached image goes over the bouncing image then the lightsaber will be mirrored and activate a sound. If this at all makes sense...
I have the bouncing image part down so far, but I am unable to make the mousePressed() function work. like I mentioned, I need the "lightsaber.png" to flip when the mouse is pressed. Also, when the mouse is pressed and is directly over the JarJar image, how would I add a score count and sound event?
Thank you!
here is my code so far:
let jarJar;
let jarJarX=5;
let jarJarY=5;
let xspeed;
let yspeed;
let lightSaber;
function preload() {
jarJar = loadImage('jarjar.png');
lightSaber= loadImage ('lightSaber.png');
}
function setup() {
createCanvas(700,700);
xspeed=random (15,22);
yspeed=random (15,22);
}
function draw() {
background(0);
image (lightSaber,mouseX,mouseY,100,100);
image(jarJar,jarJarX,jarJarY, 140, 200);
jarJarX= jarJarX+xspeed;
if (jarJarX<=-300|| jarJarX>=width+200){
xspeed=xspeed*-1;
}
jarJarY= jarJarY+yspeed;
if (jarJarY<-200|| jarJarY>=height+200 ){
yspeed=yspeed*-1;
}
//picture mirrors when mouse pressed
if mouseClicked(){
scale(-1,1);
image(lightSaber);
}
//score counter coordinate with lightsaber hitting image
//
}
Let it be known that I'm not proficient at javaScript. This said, your question is quite simple so I can help anyway.
Some framework will have simple ways to mirror images. Processing likes to scale with a negative number. I re-coded some of your stuff to accommodate my changes. The main changes goes as follows:
I added a method to draw the lightsaber so we can "animate" it (read: flip it for a couple frames when the user clicks around).
I added a 'score' global variable to track the score, and a way for the user to see that score with the text method.
I added a method called "intersect" which isn't very well coded as it's something I did back when I was a student (please don't hurt me, it works just right so I still use it from time to time). For more details on how simple collisions works, take some time to read this answer I wrote some time ago, there are nice pictures too!
I added a mouseClicked method. This method will act like an event, which means that it will be triggered by a specific call (a left mouse button click in this case). This method contains the code to check for a collision between the squares which are the images. If there's an overlap, the score will increase and jarjar will run in another direction (this part is a bonus to demonstrate that this is the place where you can get creative about the collision).
I commented the code so you can get what I'm doing more easily:
let jarJar;
let jarJarX=5;
let jarJarY=5;
let xspeed;
let yspeed;
let lightSaber;
let flipLength;
let score = 0;
function preload() {
jarJar = loadImage('jarjar.png');
lightSaber= loadImage ('lightSaber.png');
}
function setup() {
createCanvas(700, 700);
runJarJarRun();
}
function draw() {
background(0);
drawLightSaber(); // this way I can deal with the lightsaber's appearance in a dedicated method
image(jarJar, jarJarX, jarJarY, 140, 200);
jarJarX= jarJarX+xspeed;
if (jarJarX<=-300|| jarJarX>=width+200) {
xspeed=xspeed*-1;
}
jarJarY= jarJarY+yspeed;
if (jarJarY<-200|| jarJarY>=height+200 ) {
yspeed=yspeed*-1;
}
//score counter coordinate with lightsaber hitting image
textSize(30);
fill(200, 200, 0);
text('Score: ' + score, 10, 40);
}
function drawLightSaber() {
if (flipLength) { // if the number is > 0 this will be true
flipLength--; // measure how ling the saber is flipped in frames # ~60 frames per second
push(); // isolating the translate ans scale manpulations to avoid ruining the rest of the sketch
translate(mouseX + 100, 0); // makes the coordinates so once flipped the lightsaber will still appear at the same location
scale(-1.0, 1.0); // flip x-axis backwards
image (lightSaber, 0, mouseY, 100, 100);
pop(); // ends the sequence started with 'push();'
} else {
image (lightSaber, mouseX, mouseY, 100, 100);
}
}
function runJarJarRun() {
xspeed=random (5, 10);
yspeed=random (5, 10);
}
function mouseClicked() { // this method will trigger once when the left mouse button is clicked
flipLength = 10;
if (intersect(jarJarX, jarJarY, 140, 200, mouseX, mouseY, 100, 100)) {
score++;
runJarJarRun(); // as a bonus, jarjar will run in another direction on hit
// you could totally put some more special effects, like a flash, a sound, some 'mesa ouchie bad!' text, whatever speaks to you
}
}
function intersect(x1, y1, w1, h1, x2, y2, w2, h2) {
let checkX = false;
let checkY = false;
if ( (x1<x2 && (x1+w1)>x2) || (x1<(x2+w2) && (x1+w1)>x2+w2) || (x1>x2 && (x1+w1)<(x2+w2)) ) {
checkX = true;
}
if ( (y1<y2 && (y1+h1)>y2) || (y1<(y2+h2) && (y1+h1)>y2+h2) || (y1>y2 && (y1+h1)<(y2+h2)) ) {
checkY = true;
}
return (checkX && checkY);
}
If there's something you don't understand, let me know in a comment and I'll be happy to elaborate. Good luck and have fun!
Hi and welcome to stack overflow. One thing to keep in mind when submitting here (or any forum where you're looking for help with code) is to post a minimal reproducible example. You'll be much more likely to get useful responses.
You'll also want to separate out your questions, as they each have multi-step responses.
Your first question is about how to get your sketch to display something when you press the mouse down. Your syntax isn't quite correct there. Here's a minimal example of how to check for a mouse held down.
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
if (mouseIsPressed == true) {
ellipse(100, 100, 100, 100);
}
}
Just a quick note that I tried to make this as 'novice-friendly' as possible. The == true is optional and not usually included.
I'm trying to build a very simple animation function. I'm using this tutorial to build my project:
https://www.youtube.com/watch?v=hUCT4b4wa-8
The result after the button is clicked should be a green box moving across the page from left to right. When the button is clicked, nothing happens and I don't get any console errors.
Here's my fiddle:
https://jsfiddle.net/xkhpmrtu/7/
And here's a snippet of my code:
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<style type="text/css">
canvas {
border: 1px solid #666;
}
</style>
<script type="application/javascript" language="javascript">
function anim(x,y) {
var canvas = document.getElementById('canvas');//reference to canvas element on page
var ctx = canvas.getContext('2d');//establish a 2d context for the canvas element
ctx.save();//save canvas state if required (not required for the tutoriral anaimation, but doesn't hurt the script so it stays for now)
ctx.clearRect(0, 0, 550, 400);//clears the canvas for redrawing the scene.
ctx.fillStyle = "rgba(0,200,0,1)";//coloring the rectangle
ctx.fillRect = (x, 20, 50, 50);//drawing the rectangle
ctx.restore();//this restores the canvas to it's original state when we saved it on (at the time) line 18
x += 5; //increment the x position by some numeric value
var loopTimer = setTimeout('draw('+x+','+y+')', 2000);// setTimeout is a function that
</script>
</head>
<body>
<button onclick="animate(0,0)">Draw</button>
<canvas id="canvas" width="550" height="400"></canvas>
</body>
Any idea what I'm doing wrong?
I just had a look at the tutorial link. I will give if a major thumbs down as it demonstrates how not to animate and how not to do many other things in Javascript.
First the script tag and what is wrong with it
// type and language default to the correct setting for javascrip
// <script type="application/javascript" language="javascript">
<script>
function anim(x,y) {
// get the canvas once. Getting the canvas for each frame of an
// animation will slow everything down. Same for ctx though will not
// create as much of a slowdown it is not needed for each frame
// var canvas = document.getElementById('canvas');
// var ctx = canvas.getContext('2d');
// Dont use save unless you have to. It is not ok to add it if not needed
// ctx.save();
// dont use literal values, canvas may change size
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "rgba(0,200,0,1)";
// this line is wrong should be ctx.fillRect(x, 20, 50, 50). It is correct in the video
ctx.fillRect = (x, 20, 50, 50);//drawing the rectangle
// restore not needed
//ctx.restore();
x += 5; //increment the x position by some numeric value
// creating a string for a timer is bad. It invokes the parser and is slooowwwwww...
// For animations you should avoid setTimeout altogether and use
// requestAnimationFrame
// var loopTimer = setTimeout('draw('+x+','+y+')', 2000);
requestAnimationFrame(draw);
// you were missing the closing curly.
}
</script>
There is lots more wrong with the tut. It can be excused due to it being near 5 years old. You should look for more up todate tutorials as 5 years is forever in computer technology.
Here is how to do it correctly.
// This script should be at the bottom of the page just befor the closing body tag
// If not you need to use the onload event to start the script.
// define a function that starts the animation
function startAnimation() {
animating = true; // flag we are now animating
x = 10;
y = 10;
// animation will start at next frame or restart at next frame if already running
}
// define the animation function
function anim() {
if (animating) { // only draw if animating
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "red"; //coloring the rectangle
ctx.fillRect(x, y, 50, 50); //drawing the rectangle
x += xSpeed;
}
// set animation timer for next frame
requestAnimationFrame(anim);
}
// add a click listener to the start button. It calls the supplied function every time you click the button
startAnimButton.addEventListener("click", startAnimation);
const ctx = canvas.getContext('2d'); // get the 2d rendering context
// set up global variables to do the animation
var x, y, animating;
animating = false; // flag we are not animating
const xSpeed = 50 / 60; // Speed is 50 pixels per second at 60fps
// dont slow the animation down via frame rate
// slow it down by reducing speed.
// You only slow frame rate if the machine
// can not handle the load.
// start the animation loop
requestAnimationFrame(anim);
canvas {
border: 1px solid #666;
}
<!-- don't add events inline -->
<button id="startAnimButton">Draw</button>
<canvas id="canvas" width="512" height="128"></canvas>
So, I'm trying to create a laser effect, similar to the one located at http://map.norsecorp.com/
For this example, I have a 500x500 canvas. The current javascript part of the solution is located below:
function shootLaser(x, y) {
var beam = new createjs.Shape();
beam.graphics.beginFill("red");
beam.graphics.moveTo(0,1.5).lineTo(70,0).lineTo(70,3).closePath();
beam.x = 80;
beam.y = 50;
stage.addChild(beam);
beam.setBounds(0,0,70,3);
createjs.Tween.get(beam,{ loop: true, onChange: beamUpdate })
.to({ x: 400 }, 1000, createjs.Ease.linear());
}
function beamUpdate(e) {
var beam = e.currentTarget.target;
var targetX = e.currentTarget._curQueueProps.x;
if( targetX - beam.x < beam.getBounds().width ) {
beam.scaleX = (targetX - beam.x) / targetX;
} else {
beam.scaleX = 1;
}
}
This draws the line the way that I want to. However the scaleX method doesn't quite work (not even close really, it just gets extremely small very fast).
The problem is that I can't find a way to shrink the "laser" once it hits it's target. If I shoot it from 0px to 250px. It should hit 250px and begin shrinking until the 250th pixel has "consumed" it for lack of a better term. Any help is greatly appreciated.
P.S. I'm also open to doing this with other libraries or tools. I just haven't found them yet.
I have been trying to set up a javascript game loop and I have two issues I am running into. I find that in chrome when I lose focus of the browser window and then click back the animation I have running does this weird "catch up" thing where it quickly runs through the frames it should of been rendering in the background. I also have noticed that the animation is blury when moving at the current speed I have it at yet other people have been able to get their canvas drawings to move quickly and still look crisp. I know their seems to be a lot out about this but I cant make sense of what my issue really is. I thought this was a recommended way to create a game loop.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Frame Test</title>
<link href="/css/bootstrap.css" media="all" rel="stylesheet" type="text/css" />
<script language="javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"
type="text/javascript">
</script>
<script language="javascript" src="js/jquery.hotkeys.js" type="text/javascript"></script>
<script language="javascript" src="js/key_status.js" type="text/javascript"></script>
<script language="javascript" src="js/util.js" type="text/javascript"></script>
<script language="javascript" src="js/sprite.js" type="text/javascript"></script>
</head>
<body>
<button id="button1">
Toggle Loop</button>
<h1 id="frameCount">
Game Loop Test</h1>
<canvas id="gameCanvas" width="800" height="500">
<p>Your browser doesn't support canvas.</p>
</canvas>
<script type='text/javascript'>
// demo code used for playing around with javascript-canvas animations
var frameCount = 0;
var drawingCanvas = document.getElementById('gameCanvas');
// Check the element is in the DOM and the browser supports canvas
if (drawingCanvas.getContext) {
var context = drawingCanvas.getContext('2d');
var x = 100;
var y = 100;
var right = true;
context.strokeStyle = "#000000";
context.fillStyle = "Green";
context.beginPath();
context.arc(x, y, 50, 0, Math.PI * 2, true);
context.closePath();
context.stroke();
context.fill();
}
function Timer(settings) {
this.settings = settings;
this.timer = null;
this.on = false; //Bool that represents if the timer is running or stoped
this.fps = settings.fps || 30; //Target frames per second value
this.interval = Math.floor(1000 / 30);
this.timeInit = null; //Initial time taken when start is called
return this;
}
Timer.prototype =
{
run: function () {
var $this = this;
this.settings.run();
this.timeInit += this.interval;
this.timer = setTimeout(
function () { $this.run() },
this.timeInit - (new Date).getTime()
);
},
start: function () {
if (this.timer == null) {
this.timeInit = (new Date).getTime();
this.run();
this.on = true;
}
},
stop: function () {
clearTimeout(this.timer);
this.timer = null;
this.on = false;
},
toggle: function () {
if (this.on) { this.stop(); }
else { this.start(); }
}
}
var timer = new Timer({
fps: 30,
run: function () {
//---------------------------------------------run game code here------------------------------------------------------
//Currently Chorme is playing a catch up game with the frames to be drawn when the user leaves the browser window and then returns
//A simple canvas animation is drawn here to try and figure out how to solve this issue. (Most likely related to the timer implimentation)
//Once figured out probably the only code in this loop should be something like
//updateGameLogic();
//updateGameCanvas();
frameCount++;
if (drawingCanvas.getContext) {
// Initaliase a 2-dimensional drawing context
//Canvas commands go here
context.clearRect((x - 52), 48, (x + 52), 104);
// Create the yellow face
context.strokeStyle = "#000000";
context.fillStyle = "Green";
context.beginPath();
if (right) {
x = x + 6;
if (x > 500)
right = false;
} else {
x = x - 6;
if (x < 100)
right = true;
}
context.arc(x, 100, 50, 0, Math.PI * 2, true);
context.closePath();
context.stroke();
context.fill();
}
document.getElementById("frameCount").innerHTML = frameCount;
//---------------------------------------------end of game loop--------------------------------------------------------
}
});
document.getElementById("button1").onclick = function () { timer.toggle(); };
frameCount++;
document.getElementById("frameCount").innerHTML = frameCount;
</script>
</body>
</html>
-------------Update ---------------------
I have used requestanimation frame and that has solved the frame rate problam but I still get weird ghosting/bluring when the animation is running. any idea how I should be drawing this thing?
Okay, so part of your problem is that when you switch tabs, Chrome throttles down its performance.
Basically, when you leave, Chrome slows all of the calculations on the page to 1 or 2 fps (battery-saver, and more performance for the current tab).
Using setTimeout in the way that you have is basically scheduling all of these calls, which sit and wait for the user to come back (or at most are only running at 1fps).
When the user comes back, you've got hundreds of these stacked calls, waiting to be handled, and because they've all been scheduled earlier, they've all passed their "wait" time, so they're all going to execute as fast as possible (fast-forward), until the stack is emptied to where you have to start waiting 32ms for the next call.
A solution to this is to stop the timer when someone leaves -- pause the game.
On some browsers which support canvas games in meaningful ways, there is also support for a PageVisibility API. You should look into it.
For other browsers, it'll be less simple, but you can tie to a blur event on the window for example.
Just be sure that when you restart, you also clear your interval for your updates.
Ultimately, I'd suggest moving over to `requestAnimationFrame, because it will intelligently handle frame rate, and also handle the throttling you see, due to the stacked calls, but your timer looks like a decent substitute for browsers which don't yet have it.
As for blurriness, that needs more insight.
Reasons off the top of my head, if you're talking about images, are either that your canvas' width/height are being set in CSS, somewhere, or your sprites aren't being used at a 1:1 scale from the image they're pulled from.
It can also come down to sub-pixel positioning of your images, or rotation.
Hope that helps a little.
...actually, after looking at your code again, try removing "width" and "height" from your canvas in HTML, and instead, change canvas.width = 800; canvas.height = 500; in JS, and see if that helps any.
I'm starting to program a javascript tower defense; so far i have the movement of the minions over a trajectory. But I have a very big trouble, the game suddenly freezes for a couple of seconds. I'm guessing that is the garbage collector doing its job, any ideas on how i can solve this will be very good since i plan on adding a lot more of elements to the game and i don't want to keep coding till i get this flowing perfectly!
The code so far is pretty simple; you can check it out here
Here's the code:
<html>
<head>
<style>
#game{
background:red;
width:500px;
height:500px;
position:relative;
}
.mostro {
background:black;
width:15px;
height:15px;
position:absolute;
}
</style>
</head>
<body>
<div id="game">
<script type="text/javascript">
waypoint_x = [40, 140, 140, 220, 220, 80, 80, 340, 340, 420, 420];
waypoint_y = [140, 140, 60, 60, 240, 240, 320, 320, 100, 100, -20];
delay = 25;
new_monster = 0;
monsters_placed = 0;
monsters = [];
var d = new Date();
dist_x = 0;
dist_y = 0;
angle = 0;
mostro="";
total_monsters = 5;
function runGame() {
if (monsters_placed<total_monsters) {
new_monster++;
}
if (new_monster == delay) {
new_monster = 0;
document.getElementById("game").innerHTML = document.getElementById("game").innerHTML + '<div class="mostro" id="mostro-'+monsters_placed+'"></div>';
monsters_placed++;
}
for (i=0;i<monsters_placed;i=i+1) {
mostro = monsters[i];
dist_x = waypoint_x[mostro.point_to_reach] - mostro._x;
dist_y = waypoint_y[mostro.point_to_reach] - mostro._y;
if ((Math.abs(dist_x) + Math.abs(dist_y)) < 1) {
monsters[i].point_to_reach++;
}
angle = Math.atan2(dist_y, dist_x);
mostro._x = mostro._x + mostro.speed * Math.cos(angle);
mostro._y = mostro._y + mostro.speed * Math.sin(angle);
monsters[i]._rotation = angle/Math.PI*180-90
document.getElementById("mostro-"+i).style.left = Math.ceil(mostro._x) + "px";
document.getElementById("mostro-"+i).style.top = Math.ceil(mostro._y) + "px";
}
}
function setUpGame(){
for(i=0;i<=total_monsters;i++){
monsters[i] = new Object();
monsters[i].point_to_reach = 0;
monsters[i].speed = 1;
monsters[i]._x = 0;
monsters[i]._y = 0;
}
}
setUpGame();
setInterval(runGame,10);
</script>
</body>
</html>
Its not the garbage collector doing the job but in your code when you try to set the top and left positions, at a particuar time the value that you try to set in not a number. So the code breaks....
I think this occurs when the moving div crosses the top of the container with red background.
Yes, thats right: the delay is because when there are too many monsters, there are too many position updates that need to be done. This causes the "redraw" delay..
I see that there is a DOM element for each monster(as should be the case). But, you are updating their positions one by one.
Tips to reduce this lag:
Firstly, it would be a better stategy to update their positions en masse:
<div id='monster-container'>
<div id='monstser-1'></div>
<div id='monstser-2'></div>
<div id='monstser-3'></div>
</div>
So update the position of '#monster-container' when the monsters move. This way redraw time will definitely be minimized. What I say is from a primitive understanding of your game. You may need to modify this approach depending upon the path of the monsters. My approach will work directly only if the monsters only move in a straight line.
Secondly, if you are using img's for the monsters, consider using div's, and set the images as backgrounds of the div. This has given faster redraw performance in many of my pet games.
Thirdly, if you are using individual images for the monsters, consider using a composite image and CSS spriting.
Wish you luck with your game! Cheers!!
jrh
Yes, that's definitely a garbage collector. I am developing a JavaScript game myself, and I spent last few days trying to get rid of this problem. So far I can say that it's impossible.
However, I would like to note that different browsers have different garbage collectors, and for example, in Safari 4, your example runs perfectly smooth.
And here is interesting link on this topic: Reducing freezing with Object Pooling
Honestly, I think, that technique described in that article is not very helpful, because even in your example, that doesn't have any variables needed to be cleared, freezing is really noticeable.
Also I've rewritten your example, to test if global variables ruined performance.
You can see the difference yourself