postext-folio 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/dist/bookGeometry.d.ts +1 -1
- package/dist/bookGeometry.d.ts.map +1 -1
- package/dist/bookGeometry.js +5 -0
- package/dist/bookGeometry.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/pageFlip.d.ts +27 -17
- package/dist/pageFlip.d.ts.map +1 -1
- package/dist/pageFlip.js +131 -85
- package/dist/pageFlip.js.map +1 -1
- package/dist/paper.d.ts +8 -1
- package/dist/paper.d.ts.map +1 -1
- package/dist/paper.js +21 -4
- package/dist/paper.js.map +1 -1
- package/dist/postext.d.ts +16 -7
- package/dist/postext.d.ts.map +1 -1
- package/dist/postext.js +172 -84
- package/dist/postext.js.map +1 -1
- package/dist/videoAtlas.d.ts +90 -0
- package/dist/videoAtlas.d.ts.map +1 -0
- package/dist/videoAtlas.js +241 -0
- package/dist/videoAtlas.js.map +1 -0
- package/dist/videos.d.ts +46 -0
- package/dist/videos.d.ts.map +1 -1
- package/dist/videos.js +55 -1
- package/dist/videos.js.map +1 -1
- package/dist/viewer.d.ts +7 -1
- package/dist/viewer.d.ts.map +1 -1
- package/dist/viewer.js +47 -39
- package/dist/viewer.js.map +1 -1
- package/package.json +3 -3
package/dist/pageFlip.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BoxGeometry, BufferAttribute, BufferGeometry, Color, CustomBlending, DepthTexture, DirectionalLight, DoubleSide, Group, HalfFloatType, LinearMipmapLinearFilter, MaxEquation, Mesh, MeshPhysicalMaterial, MeshStandardMaterial, LinearFilter, Matrix4, NeutralToneMapping, OneFactor, OrthographicCamera, PCFShadowMap, PerspectiveCamera, Plane, PlaneGeometry, PMREMGenerator, Raycaster, Scene, ShaderChunk, ShaderMaterial, ShadowMaterial, SRGBColorSpace, Texture, TextureLoader, Vector2, Vector3, Vector4,
|
|
1
|
+
import { BoxGeometry, BufferAttribute, BufferGeometry, Color, CustomBlending, DepthTexture, DirectionalLight, DoubleSide, Group, HalfFloatType, LinearMipmapLinearFilter, MaxEquation, Mesh, MeshPhysicalMaterial, MeshStandardMaterial, LinearFilter, Matrix4, NeutralToneMapping, OneFactor, OrthographicCamera, PCFShadowMap, PerspectiveCamera, Plane, PlaneGeometry, PMREMGenerator, Raycaster, Scene, ShaderChunk, ShaderMaterial, ShadowMaterial, SRGBColorSpace, Texture, TextureLoader, Vector2, Vector3, Vector4, WebGLRenderer, WebGLRenderTarget, } from "three";
|
|
2
2
|
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
|
|
3
3
|
import { OutputPass } from "three/examples/jsm/postprocessing/OutputPass.js";
|
|
4
4
|
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
|
|
@@ -8,6 +8,7 @@ import { along, BINDINGS, gutterOcclusion, profiles, stackGeometry, topAt } from
|
|
|
8
8
|
import { environment } from "./environments";
|
|
9
9
|
import { pagePaper, paperSpec } from "./paper";
|
|
10
10
|
import { loadDeskMaps } from "./deskTextures";
|
|
11
|
+
import { ATLAS_MAX, MAX_PAGE_VIDEOS, VideoAtlas } from "./videoAtlas";
|
|
11
12
|
import { cachedDesk, cachedRelief } from "./procedural";
|
|
12
13
|
/** Columns and rows of a leaf's mesh: fine enough for a tight roll. */
|
|
13
14
|
const NX = 96;
|
|
@@ -274,11 +275,11 @@ function pageMaterial(mirror, sign) {
|
|
|
274
275
|
uLeafOcc: { value: 0.45 },
|
|
275
276
|
uOccBias: { value: 6 },
|
|
276
277
|
uVideo: { value: null },
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
278
|
+
uVidTexel: { value: new Vector2(1, 1) },
|
|
279
|
+
uVidCount: { value: 0 },
|
|
280
|
+
uVidOA: { value: Array.from({ length: MAX_PAGE_VIDEOS }, () => new Vector4()) },
|
|
281
|
+
uVidDF: { value: Array.from({ length: MAX_PAGE_VIDEOS }, () => new Vector4()) },
|
|
282
|
+
uVidRect: { value: Array.from({ length: MAX_PAGE_VIDEOS }, () => new Vector4()) },
|
|
282
283
|
uReflection: { value: null },
|
|
283
284
|
uReflectionOn: { value: 0 },
|
|
284
285
|
uReflectionSize: { value: new Vector2(1, 1) },
|
|
@@ -323,11 +324,11 @@ function pageMaterial(mirror, sign) {
|
|
|
323
324
|
uniform float uLeafOcc;
|
|
324
325
|
uniform float uSign;
|
|
325
326
|
uniform sampler2D uVideo;
|
|
326
|
-
uniform
|
|
327
|
-
uniform
|
|
328
|
-
uniform
|
|
329
|
-
uniform
|
|
330
|
-
uniform vec4
|
|
327
|
+
uniform vec2 uVidTexel;
|
|
328
|
+
uniform float uVidCount;
|
|
329
|
+
uniform vec4 uVidOA[${MAX_PAGE_VIDEOS}];
|
|
330
|
+
uniform vec4 uVidDF[${MAX_PAGE_VIDEOS}];
|
|
331
|
+
uniform vec4 uVidRect[${MAX_PAGE_VIDEOS}];
|
|
331
332
|
uniform sampler2D uReflection;
|
|
332
333
|
uniform float uReflectionOn;
|
|
333
334
|
uniform vec2 uReflectionSize;
|
|
@@ -345,15 +346,22 @@ function pageMaterial(mirror, sign) {
|
|
|
345
346
|
vec2 uvB = vec2(1.0 - u, vPageUv.y);
|
|
346
347
|
vec3 ink = uPaper;
|
|
347
348
|
if (has > 0.5 && has < 1.5) ink = front ? texture2D(uFront, uvF).rgb : texture2D(uBack, uvB).rgb;
|
|
348
|
-
//
|
|
349
|
-
// point of the page (from its top left corner) in
|
|
350
|
-
// own frame, which may lie turned on the page
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
349
|
+
// The videos playing on this face, printed over their posters:
|
|
350
|
+
// the point of the page (from its top left corner) in each
|
|
351
|
+
// picture's own frame, which may lie turned on the page, then in
|
|
352
|
+
// its slot of the atlas (kept half a texel inside it, clear of
|
|
353
|
+
// the next slot).
|
|
354
|
+
vec2 tuv = front ? uvF : uvB;
|
|
355
|
+
for (int i = 0; i < ${MAX_PAGE_VIDEOS}; i++) {
|
|
356
|
+
if (float(i) >= uVidCount) break;
|
|
357
|
+
vec4 oa = uVidOA[i];
|
|
358
|
+
vec4 df = uVidDF[i];
|
|
359
|
+
if ((df.z < 1.5) != front) continue;
|
|
360
|
+
vec2 p = vec2(tuv.x, 1.0 - tuv.y) - oa.xy;
|
|
361
|
+
vec2 st = vec2(dot(p, oa.zw) / dot(oa.zw, oa.zw), dot(p, df.xy) / dot(df.xy, df.xy));
|
|
355
362
|
if (st.x >= 0.0 && st.x <= 1.0 && st.y >= 0.0 && st.y <= 1.0) {
|
|
356
|
-
|
|
363
|
+
vec4 r = uVidRect[i];
|
|
364
|
+
vec2 v = clamp(r.xy + st * r.zw, r.xy + 0.5 * uVidTexel, r.xy + r.zw - 0.5 * uVidTexel);
|
|
357
365
|
ink = texture2D(uVideo, vec2(v.x, 1.0 - v.y)).rgb;
|
|
358
366
|
}
|
|
359
367
|
}
|
|
@@ -1123,7 +1131,8 @@ export class PageFlipper {
|
|
|
1123
1131
|
setAppearance(appearance) {
|
|
1124
1132
|
this.appearance = appearance;
|
|
1125
1133
|
this.resolved = resolveFolioConfig(withStockForExtent(appearance.folio, this.pageCount(appearance)));
|
|
1126
|
-
|
|
1134
|
+
const mm = appearance.pageWidthMm;
|
|
1135
|
+
this.bookSpec = paperSpec(this.resolved.paper, mm);
|
|
1127
1136
|
// The settings now give the view the reader orbited to (it was just
|
|
1128
1137
|
// saved as the book's): they drive it again, so editing them moves it.
|
|
1129
1138
|
const { yaw, pitch } = this.orbit;
|
|
@@ -1140,20 +1149,22 @@ export class PageFlipper {
|
|
|
1140
1149
|
const key = JSON.stringify(own);
|
|
1141
1150
|
let spec = specs.get(key);
|
|
1142
1151
|
if (!spec)
|
|
1143
|
-
specs.set(key, (spec = paperSpec(pagePaper(appearance.folio, own))));
|
|
1152
|
+
specs.set(key, (spec = paperSpec(pagePaper(appearance.folio, own), mm)));
|
|
1144
1153
|
return spec;
|
|
1145
1154
|
});
|
|
1146
1155
|
const r = this.resolved;
|
|
1147
1156
|
const covers = appearance.coverLeaves;
|
|
1148
1157
|
const ownCovers = !!covers && (covers.front !== undefined || covers.back !== undefined);
|
|
1149
|
-
|
|
1158
|
+
// A newspaper's front page is the outer sheet, no heavier than the
|
|
1159
|
+
// others: it turns as a page does.
|
|
1160
|
+
this.coverSpec = !ownCovers || r.binding.type === "folded"
|
|
1150
1161
|
? null
|
|
1151
1162
|
: r.binding.type === "saddleStitch"
|
|
1152
1163
|
? // A stapled booklet's cover is a sheet like the others, of the same
|
|
1153
1164
|
// finish and a little heavier: it bends and turns as a page does.
|
|
1154
|
-
paperSpec({ ...r.paper, grammage: Math.min(350, Math.round(r.paper.grammage * 1.5)), showThrough: false })
|
|
1165
|
+
paperSpec({ ...r.paper, grammage: Math.min(350, Math.round(r.paper.grammage * 1.5)), showThrough: false }, mm)
|
|
1155
1166
|
: {
|
|
1156
|
-
...paperSpec({ ...r.paper, type: "board", grammage: 1250, bulk: 1.6, finish: "silk", texture: "smooth", shade: { hex: "#ffffff", model: "hex" }, showThrough: false }),
|
|
1167
|
+
...paperSpec({ ...r.paper, type: "board", grammage: 1250, bulk: 1.6, finish: "silk", texture: "smooth", shade: { hex: "#ffffff", model: "hex" }, showThrough: false }, mm),
|
|
1157
1168
|
// The book's own printed covers: in a case binding a printed
|
|
1158
1169
|
// (litho-laminated) case, on the case's 2–3 mm board; on a
|
|
1159
1170
|
// paperback a laminated cover card, about 0.3 mm.
|
|
@@ -1201,9 +1212,17 @@ export class PageFlipper {
|
|
|
1201
1212
|
c.clearcoat = mat === "paper" ? 0.35 : 0;
|
|
1202
1213
|
c.normalMap?.dispose();
|
|
1203
1214
|
c.normalMap = mat === "cloth" ? cachedRelief("linen").normal.clone() : mat === "leather" ? cachedDesk("leather").normal.clone() : null;
|
|
1215
|
+
if (r.binding.type === "folded") {
|
|
1216
|
+
// No cover at all: the back of the fold is the outer sheet's paper.
|
|
1217
|
+
c.color.set(r.paper.shade.hex);
|
|
1218
|
+
c.roughness = this.bookSpec.roughness;
|
|
1219
|
+
c.sheen = this.bookSpec.sheen;
|
|
1220
|
+
c.sheenColor.set(1, 1, 1);
|
|
1221
|
+
c.clearcoat = this.bookSpec.clearcoat;
|
|
1222
|
+
}
|
|
1204
1223
|
c.needsUpdate = true;
|
|
1205
|
-
// The spine.
|
|
1206
|
-
const spine = r.binding.type === "saddleStitch" ? null : (appearance.spineImage ?? null);
|
|
1224
|
+
// The spine: none on a stapled or folded book.
|
|
1225
|
+
const spine = r.binding.type === "saddleStitch" || r.binding.type === "folded" ? null : (appearance.spineImage ?? null);
|
|
1207
1226
|
if (spine !== this.spineSrc) {
|
|
1208
1227
|
this.spineSrc = spine;
|
|
1209
1228
|
this.spineTex?.dispose();
|
|
@@ -1463,8 +1482,8 @@ export class PageFlipper {
|
|
|
1463
1482
|
const tR = thick(right, extra.after);
|
|
1464
1483
|
const binding = this.resolved.binding.type;
|
|
1465
1484
|
// A board on top of a stack lies flat; the document's own covers
|
|
1466
|
-
// replace the case.
|
|
1467
|
-
const noCase = !!this.coverSpec;
|
|
1485
|
+
// replace the case, and folded sheets have none.
|
|
1486
|
+
const noCase = !!this.coverSpec || binding === "folded";
|
|
1468
1487
|
const rigid = (leaf) => leaf !== undefined && this.specOf(leaf).rigidity > 0.5;
|
|
1469
1488
|
const { left: pl, right: pr, board } = profiles(binding, this.W, k, tL, tR, {
|
|
1470
1489
|
flatLeft: rigid(left[left.length - 1]),
|
|
@@ -1529,7 +1548,7 @@ export class PageFlipper {
|
|
|
1529
1548
|
this.stacks.push(mesh);
|
|
1530
1549
|
this.stage.add(mesh);
|
|
1531
1550
|
}
|
|
1532
|
-
if (noCase)
|
|
1551
|
+
if (noCase && binding !== "folded")
|
|
1533
1552
|
this.coverMaterial.color.copy(this.boardColor());
|
|
1534
1553
|
// The back of the block: the folds sewn at the spine, under the line
|
|
1535
1554
|
// where the two open pages meet (nothing shows through the gutter).
|
|
@@ -1653,6 +1672,9 @@ export class PageFlipper {
|
|
|
1653
1672
|
mesh.material.userData.spec = null;
|
|
1654
1673
|
}
|
|
1655
1674
|
this.buildBook();
|
|
1675
|
+
// The videos' slots follow the size the pages are seen at.
|
|
1676
|
+
if (this.videos.length)
|
|
1677
|
+
this.packVideos();
|
|
1656
1678
|
// The desk: far wider than the view, tiled at its physical scale.
|
|
1657
1679
|
const k = this.pxPerMm();
|
|
1658
1680
|
const size = 40 * Math.max(W, H);
|
|
@@ -1818,75 +1840,99 @@ export class PageFlipper {
|
|
|
1818
1840
|
mesh.material.userData.uniforms.uPaper.value.setRGB(r, g, b, SRGBColorSpace);
|
|
1819
1841
|
this.redraw();
|
|
1820
1842
|
}
|
|
1821
|
-
/** The
|
|
1822
|
-
|
|
1843
|
+
/** The videos playing on the pages (#477, #507). */
|
|
1844
|
+
videos = [];
|
|
1845
|
+
/** Their pictures, drawn into one texture. */
|
|
1846
|
+
atlas = null;
|
|
1847
|
+
/** The slot sizes the atlas was packed for. */
|
|
1848
|
+
atlasKey = "";
|
|
1823
1849
|
/**
|
|
1824
|
-
* Draws
|
|
1825
|
-
* {@link PageVideoFrame}), over
|
|
1826
|
-
* whichever leaf carries
|
|
1827
|
-
* bends with the paper.
|
|
1828
|
-
*
|
|
1850
|
+
* Draws videos on the pages whose sources are their `src` (see
|
|
1851
|
+
* {@link PageVideoFrame}), over their paintings, on whichever face of
|
|
1852
|
+
* whichever leaf carries each page: lying open or turning, a picture
|
|
1853
|
+
* bends with the paper. Any number play together, up to
|
|
1854
|
+
* `MAX_PAGE_VIDEOS` (8) drawn at once; an empty list takes them all off.
|
|
1855
|
+
* The book is drawn again at every new frame of any of them.
|
|
1829
1856
|
*/
|
|
1857
|
+
setVideos(videos) {
|
|
1858
|
+
const crop = (v) => JSON.stringify(v.frame.crop ?? null);
|
|
1859
|
+
// The same pictures (a page painted on a new canvas, a layout that
|
|
1860
|
+
// moved one): the atlas stays as it is unless their sizes changed.
|
|
1861
|
+
const same = videos.length === this.videos.length && videos.every((v, i) => v.element === this.videos[i].element && crop(v) === crop(this.videos[i]));
|
|
1862
|
+
this.videos = videos.slice();
|
|
1863
|
+
if (!same)
|
|
1864
|
+
this.atlasKey = "";
|
|
1865
|
+
this.packVideos();
|
|
1866
|
+
this.dressVideos();
|
|
1867
|
+
this.redraw();
|
|
1868
|
+
}
|
|
1869
|
+
/** One video on a page, or none (see {@link setVideos}). */
|
|
1830
1870
|
setVideo(video) {
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
}
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1871
|
+
this.setVideos(video ? [video] : []);
|
|
1872
|
+
}
|
|
1873
|
+
/** Packs the videos' pictures into the atlas, each at about the size it
|
|
1874
|
+
* is seen on screen at rest, again when the book's size changes. */
|
|
1875
|
+
packVideos() {
|
|
1876
|
+
const sizes = this.videos.map(({ frame }) => {
|
|
1877
|
+
const w = Math.hypot(frame.across.x * this.W, frame.across.y * this.H) * this.dpr;
|
|
1878
|
+
const h = Math.hypot(frame.down.x * this.W, frame.down.y * this.H) * this.dpr;
|
|
1879
|
+
return { width: Math.max(16, Math.round(w)), height: Math.max(16, Math.round(h)) };
|
|
1880
|
+
});
|
|
1881
|
+
const key = this.videos.map((v, i) => `${sizes[i].width}x${sizes[i].height}`).join(",") + `|${this.videos.length}`;
|
|
1882
|
+
if (key === this.atlasKey && (this.atlas || !this.videos.length))
|
|
1883
|
+
return;
|
|
1884
|
+
this.atlasKey = key;
|
|
1885
|
+
if (!this.videos.length) {
|
|
1886
|
+
this.atlas?.dispose();
|
|
1887
|
+
this.atlas = null;
|
|
1848
1888
|
}
|
|
1849
|
-
|
|
1850
|
-
this.
|
|
1889
|
+
else {
|
|
1890
|
+
const max = Math.min(ATLAS_MAX, this.renderer.capabilities.maxTextureSize ?? ATLAS_MAX);
|
|
1891
|
+
this.atlas ??= new VideoAtlas((first) => {
|
|
1892
|
+
if (first)
|
|
1893
|
+
this.dressVideos();
|
|
1894
|
+
this.redraw();
|
|
1895
|
+
}, max);
|
|
1896
|
+
this.atlas.set(this.videos.map((v, i) => ({ element: v.element, ...(v.frame.crop ? { crop: v.frame.crop } : {}), ...sizes[i] })));
|
|
1897
|
+
}
|
|
1898
|
+
this.dressVideos();
|
|
1851
1899
|
this.redraw();
|
|
1852
1900
|
}
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
const v = this.video;
|
|
1857
|
-
if (!v)
|
|
1858
|
-
return;
|
|
1859
|
-
const el = v.element;
|
|
1860
|
-
const next = () => {
|
|
1861
|
-
if (this.video?.element !== el || this.disposed)
|
|
1862
|
-
return;
|
|
1863
|
-
this.redraw();
|
|
1864
|
-
v.callback = el.requestVideoFrameCallback ? el.requestVideoFrameCallback(next) : requestAnimationFrame(next);
|
|
1865
|
-
if (this.video)
|
|
1866
|
-
this.video.callback = v.callback;
|
|
1867
|
-
};
|
|
1868
|
-
v.callback = el.requestVideoFrameCallback ? el.requestVideoFrameCallback(next) : requestAnimationFrame(next);
|
|
1901
|
+
dressVideos() {
|
|
1902
|
+
for (const mesh of this.pageMeshes())
|
|
1903
|
+
this.dressVideo(mesh);
|
|
1869
1904
|
}
|
|
1870
1905
|
/** The meshes that show pages: the open ones, the leaves in the air and
|
|
1871
1906
|
* the block. */
|
|
1872
1907
|
pageMeshes() {
|
|
1873
1908
|
return [this.left, this.right, ...this.leaves.values(), ...(this.blockMesh ? [this.blockMesh] : [])];
|
|
1874
1909
|
}
|
|
1875
|
-
/** Sets a mesh's video uniforms: on the
|
|
1876
|
-
*
|
|
1910
|
+
/** Sets a mesh's video uniforms: the videos on the faces that show their
|
|
1911
|
+
* pages (once their pictures are in the atlas), none elsewhere. */
|
|
1877
1912
|
dressVideo(mesh) {
|
|
1878
1913
|
const u = mesh.material.userData.uniforms;
|
|
1879
|
-
const
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1914
|
+
const atlas = this.atlas;
|
|
1915
|
+
let n = 0;
|
|
1916
|
+
for (const v of atlas ? this.videos : []) {
|
|
1917
|
+
if (n >= MAX_PAGE_VIDEOS)
|
|
1918
|
+
break;
|
|
1919
|
+
// A blank page ("") is no page of its own: it shows no video.
|
|
1920
|
+
const face = v.src ? (mesh.userData.Front === v.src ? 1 : mesh.userData.Back === v.src ? 2 : 0) : 0;
|
|
1921
|
+
const rect = face ? atlas.rectOf(v.element) : null;
|
|
1922
|
+
if (!rect)
|
|
1923
|
+
continue;
|
|
1924
|
+
const { origin, across, down } = v.frame;
|
|
1925
|
+
u.uVidOA.value[n].set(origin.x, origin.y, across.x, across.y);
|
|
1926
|
+
u.uVidDF.value[n].set(down.x, down.y, face, 0);
|
|
1927
|
+
u.uVidRect.value[n].set(rect.x, rect.y, rect.width, rect.height);
|
|
1928
|
+
n++;
|
|
1929
|
+
}
|
|
1930
|
+
u.uVidCount.value = n;
|
|
1931
|
+
u.uVideo.value = n ? atlas.texture : null;
|
|
1932
|
+
if (n) {
|
|
1933
|
+
const size = atlas.size;
|
|
1934
|
+
u.uVidTexel.value.set(1 / size.width, 1 / size.height);
|
|
1935
|
+
}
|
|
1890
1936
|
}
|
|
1891
1937
|
/** A page source drawn again in place (a canvas repainted): its
|
|
1892
1938
|
* texture is uploaded again and the book redrawn. */
|
|
@@ -2806,7 +2852,7 @@ export class PageFlipper {
|
|
|
2806
2852
|
}
|
|
2807
2853
|
dispose() {
|
|
2808
2854
|
this.disposed = true;
|
|
2809
|
-
this.
|
|
2855
|
+
this.setVideos([]);
|
|
2810
2856
|
cancelAnimationFrame(this.raf);
|
|
2811
2857
|
cancelAnimationFrame(this.still);
|
|
2812
2858
|
cancelAnimationFrame(this.orbitFrame);
|