Skip to content

Commit 00f3496

Browse files
committed
working on hot reloading features
1 parent 9b38b71 commit 00f3496

File tree

5 files changed

+77
-37
lines changed

5 files changed

+77
-37
lines changed

examples/template.html

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,24 @@
1111
display: flex;
1212
justify-content: center;
1313
align-items: center;
14-
flex-direction: row;
1514
flex-direction: column;
1615
}
1716

1817
body {
19-
display: flex;
2018
width: 100%;
2119
height: 100%;
22-
justify-content: space-between;
20+
display: flex;
21+
justify-content: center;
2322
align-items: center;
2423
flex-direction: row;
25-
margin: 0px;
24+
margin: 0;
2625
}
2726

2827
canvas {
2928
margin: auto;
3029
display: block;
3130
box-shadow: 0px 2px 12px -2px rgba(0, 0, 0, 0.15);
3231
}
33-
34-
.canvas-sketch-gui {
35-
width: 256px;
36-
height: 256px;
37-
background: blue;
38-
}
3932
</style>
4033
</head>
4134
<body>

lib/canvas-sketch.js

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,36 @@
11
import SketchManager from './core/SketchManager';
22
import PaperSizes from './paper-sizes';
3+
import { getClientAPI } from './util';
4+
import defined from 'defined';
35

4-
const CACHE = 'canvas-sketch-file-cache';
6+
const CACHE = 'hot-id-cache';
7+
const runtimeCollisions = [];
58

6-
function cacheGet (file) {
7-
window[CACHE] = window[CACHE] || {};
8-
return window[CACHE][file];
9+
function isHotReload () {
10+
const client = getClientAPI();
11+
return client && client.hot;
912
}
1013

11-
function cachePut (file, data) {
12-
window[CACHE] = window[CACHE] || {};
13-
window[CACHE][file] = data;
14+
function cacheGet (id) {
15+
const client = getClientAPI();
16+
if (!client) return undefined;
17+
client[CACHE] = client[CACHE] || {};
18+
return client[CACHE][id];
1419
}
1520

16-
function canvasSketch (sketch, settings = {}, file) {
21+
function cachePut (id, data) {
22+
const client = getClientAPI();
23+
if (!client) return undefined;
24+
client[CACHE] = client[CACHE] || {};
25+
client[CACHE][id] = data;
26+
}
27+
28+
function getTimeProp (oldManager, newSettings) {
29+
// Static sketches ignore the time persistency
30+
return newSettings.animate ? { time: oldManager.props.time } : undefined;
31+
}
32+
33+
function canvasSketch (sketch, settings = {}) {
1734
if (settings.p5) {
1835
if (settings.canvas || (settings.context && typeof settings.context !== 'string')) {
1936
throw new Error(`In { p5 } mode, you can't pass your own canvas or context, unless the context is a "webgl" or "2d" string`);
@@ -24,43 +41,60 @@ function canvasSketch (sketch, settings = {}, file) {
2441
settings = Object.assign({}, settings, { canvas: false, context });
2542
}
2643

27-
const isCaching = typeof file === 'string';
44+
const isHot = isHotReload();
45+
let hotID;
46+
if (isHot) {
47+
hotID = defined(settings.id, process.env.SKETCH_ENTRY);
48+
}
49+
let isInjecting = isHot && typeof hotID === 'string';
50+
51+
if (isInjecting && runtimeCollisions.includes(hotID)) {
52+
console.warn(`Warning: You have multiple calls to canvasSketch() in --hot mode. You must pass unique { id } strings in settings to enable hot reload across multiple sketches. `, hotID);
53+
isInjecting = false;
54+
}
2855

2956
let preload = Promise.resolve();
3057

31-
if (isCaching) {
32-
const previousData = cacheGet(file);
58+
if (isInjecting) {
59+
// Mark this as already spotted in this runtime instance
60+
runtimeCollisions.push(hotID);
61+
62+
const previousData = cacheGet(hotID);
3363
if (previousData) {
34-
preload = previousData.load.then(manager => {
35-
const newProps = Object.assign({}, manager.props);
36-
manager.destroy();
37-
return {
38-
time: newProps.time
39-
};
40-
}).catch(() => {
41-
// If an error occurred during load, we will just
42-
// destroy old manager and reset props
64+
const next = () => {
65+
// Grab new props from old sketch instance
66+
const newProps = getTimeProp(previousData.manager, settings);
67+
// Destroy the old instance
4368
previousData.manager.destroy();
44-
return null;
45-
});
69+
// Pass along new props
70+
return newProps;
71+
};
72+
73+
// Move along the next data...
74+
preload = previousData.load.then(next).catch(next);
4675
}
4776
}
4877

4978
return preload.then(newProps => {
5079
const manager = new SketchManager();
5180
let result;
5281
if (sketch) {
82+
// Merge with incoming data
83+
settings = Object.assign({}, settings, newProps);
84+
5385
// Apply settings and create a canvas
5486
manager.setup(settings);
55-
if (newProps) manager.update(newProps);
87+
88+
// Mount to DOM
5689
manager.mount();
90+
5791
// load the sketch first
5892
result = manager.loadAndRun(sketch);
5993
} else {
6094
result = Promise.resolve(manager);
6195
}
62-
if (isCaching) {
63-
cachePut(file, { load: result, manager });
96+
if (isInjecting) {
97+
cachePut(hotID, { load: result, manager });
6498
}
6599
return result;
66100
});

lib/core/SketchManager.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,14 @@ class SketchManager {
130130
console.error('[canvas-sketch] WARN: Using { animate } in Node.js is not yet supported');
131131
return;
132132
}
133+
if (this.props.playing) return;
133134
if (!this.props.started) {
134135
this._signalBegin();
135136
this.props.started = true;
136137
}
138+
139+
// console.log('play', this.props.time)
140+
137141
// Start a render loop
138142
this.props.playing = true;
139143
if (this._raf != null) window.cancelAnimationFrame(this._raf);
@@ -144,6 +148,8 @@ class SketchManager {
144148
pause () {
145149
if (this.props.recording) this.endRecord();
146150
this.props.playing = false;
151+
152+
// console.log('pause', this.props.time)
147153
if (this._raf != null && isBrowser()) window.cancelAnimationFrame(this._raf);
148154
}
149155

@@ -717,15 +723,15 @@ class SketchManager {
717723
};
718724
}
719725

720-
setup (settings = {}) {
726+
setup (settings = {}, overrides = {}) {
721727
if (this.sketch) throw new Error('Multiple setup() calls not yet supported.');
722728

723729
this._settings = Object.assign({}, settings, this._settings);
724730

725731
// Get initial canvas & context
726732
const { context, canvas } = createCanvas(this._settings);
727733

728-
const timeProps = this.getTimeProps(settings);
734+
const timeProps = this.getTimeProps(this._settings);
729735

730736
// Initial render state features
731737
this._props = {

package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"glslify": "^6.1.1",
5656
"hex-rgb": "^3.0.0",
5757
"insert-css": "^2.0.0",
58+
"lerp": "^1.0.3",
5859
"lineclip": "^1.1.5",
5960
"load-asset": "^1.2.0",
6061
"mkdirp": "^0.5.1",

0 commit comments

Comments
 (0)