I’m working on a notebook right now where I would like to do something like the following:
speed = viewof html`<input min="0" max="10">` // units per second
position = {
let position = 0;
let lastUpdated = performance.now();
while (true) {
const currentTime = performance.now();
// it's important that the simulation run at an accurate multiple of
// "real time", hence why I'm computing the amount of time passed
// rather than just assuming the loop is running at 60 FPS.
position += speed * (currentTime - lastUpdated) / 1000;
lastUpdated = currentTime;
yield position;
}
}
car = {
let car = this;
if (!car) {
car = new THREE.Mesh();
// ... additional setup omitted ...
scene.add(car);
}
car.position.x = position;
}
Then, I’m rendering the scene to a canvas in a loop, like this:
display = {
const renderer = new THREE.WebGLRenderer({antialias: true});
try {
while (true) {
renderer.render(scene, camera);
yield renderer.domElement;
}
} finally {
renderer.dispose();
}
}
This works fine. The loop isn’t reactive to the car, but because we attach the car to the scene and then mutate its position, the loop ends up seeing new values for the car’s position each time it runs.
The problem with this setup is that when the user moves the speed
slider, the car’s position resets. I’d like the position to be preserved.
I’ve found a workaround, which is to do something like this:
mutable position = 0
{
let lastUpdated = performance.now()
while (true) {
const currentTime = performance.now();
mutable position += speed * (currentTime - lastUpdated) / 1000;
lastUpdated = currentTime;
await Promises.delay(1000 / 60);
}
}
This seems to solve the problem, since position is no longer reactive to speed. The anonymous cell which is updating position gets rerun whenever speed changes, but this doesn’t reset the position itself.
However, this seems ugly to me. Expressing position
as a generator seems more natural, but this would require somehow fetching the value of speed
within the generator’s loop without making the generator cell reactive to changes in speed
.
Is there a recommended pattern for dealing with these sorts of issues? I have a dim sense that a custom view (as demonstrated in @mbostock/synchronized-views) might solve my problem, but I don’t understand them in enough depth to really know.
Thanks,
Jake