aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatarLarge Libravatar memdmp <memdmpestrogenzone>2025-08-14 13:26:07 +0200
committerLibravatarLarge Libravatar memdmp <memdmpestrogenzone>2025-08-14 13:26:07 +0200
commit445dba26c3636f1a0695549a446e1d5a27eb87db (patch)
tree56592af6d184b13014b93073fae2b9797aec9a26
parent289c9eeb1f047dee653069bf044e3cb1a308968b (diff)
downloadvideotool-445dba26c3636f1a0695549a446e1d5a27eb87db.tar.gz
videotool-445dba26c3636f1a0695549a446e1d5a27eb87db.tar.bz2
videotool-445dba26c3636f1a0695549a446e1d5a27eb87db.tar.lz
videotool-445dba26c3636f1a0695549a446e1d5a27eb87db.zip

feat: a proxy-based OnceCell

-rw-r--r--src/user/ThreeVideo.ts60
-rw-r--r--src/user/index.ts44
2 files changed, 76 insertions, 28 deletions
diff --git a/src/user/ThreeVideo.ts b/src/user/ThreeVideo.ts
index 92615f1..828c6c9 100644
--- a/src/user/ThreeVideo.ts
+++ b/src/user/ThreeVideo.ts
@@ -2,13 +2,61 @@ import { Video as BaseVideo, type FrameTime, type InitConfig } from '$/lib/Playe
import * as THREE from 'three';
import type { OrbitControls } from 'three/examples/jsm/Addons.js';
-export const OnceCell = <T>(create: () => T) => {
- let called = false,
- cached = null as unknown as T
- return () => {
- if (called) return cached
- else { cached = create(); called = true; return cached }
+export type Proxy<T> = T
+export const OnceCell = <T>(create: () => T): Proxy<T> => {
+ let value = null as unknown as T;
+ let created = false;
+ let createOnce = (): T extends object ? T : never => {
+ // @ts-ignore
+ if (created) return value; else return (created = true, value = create())
}
+ return new Proxy({
+ get value() {
+ return createOnce()
+ }
+ }, {
+ get(_, ...args) {
+ return Reflect.get(createOnce(), ...args)
+ },
+ set(_, ...args) {
+ return Reflect.set(createOnce(), ...args)
+ },
+ has(_, ...args) {
+ return Reflect.has(createOnce(), ...args)
+ },
+ deleteProperty(_, ...args) {
+ return Reflect.deleteProperty(createOnce(), ...args)
+ },
+ isExtensible(_, ...args) {
+ return Reflect.isExtensible(createOnce(), ...args)
+ },
+ ownKeys(_, ...args) {
+ return Reflect.ownKeys(createOnce(), ...args)
+ },
+ defineProperty(_, ...args) {
+ return Reflect.defineProperty(createOnce(), ...args)
+ },
+ getOwnPropertyDescriptor(_, ...args) {
+ return Reflect.getOwnPropertyDescriptor(createOnce(), ...args)
+ },
+ preventExtensions(_, ...args) {
+ return Reflect.preventExtensions(createOnce(), ...args)
+ },
+ getPrototypeOf(_, ...args) {
+ return Reflect.getPrototypeOf(createOnce(), ...args)
+ },
+ setPrototypeOf(_, ...args) {
+ return Reflect.setPrototypeOf(createOnce(), ...args)
+ },
+ apply(_, ...args) {
+ type F = (this: any, ...args: any[]) => any
+ return Reflect.apply(createOnce() as unknown as T extends F ? F : never, ...args)
+ },
+ construct(_, ...args) {
+ type F = (this: any, ...args: any[]) => any
+ return Reflect.construct(createOnce() as unknown as T extends F ? F : never, ...args)
+ },
+ }) as Proxy<T>
}
export default abstract class ThreeVideo extends BaseVideo {
diff --git a/src/user/index.ts b/src/user/index.ts
index 541cd94..b4f0501 100644
--- a/src/user/index.ts
+++ b/src/user/index.ts
@@ -71,9 +71,9 @@ export default class Video extends ThreeVideo {
metalness: 0.2,
bumpScale: 1
}));
- protected uiDark = OnceCell(() => new THREE.Mesh(this.uiGeometry(), this.uiDarkMaterial()))
+ protected uiDark = OnceCell(() => new THREE.Mesh(this.uiGeometry, this.uiDarkMaterial))
protected uiLightMaterial = OnceCell(() => new THREE.MeshBasicMaterial({ color: 0x000000 }))
- protected uiLight = OnceCell(() => new THREE.Mesh(this.uiGeometry(), this.uiLightMaterial()))
+ protected uiLight = OnceCell(() => new THREE.Mesh(this.uiGeometry, this.uiLightMaterial))
protected lighting = OnceCell(() => {
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.castShadow = true;
@@ -99,7 +99,7 @@ export default class Video extends ThreeVideo {
c.height = c.width / 5 * 7;
return c;
});
- protected uiCanvasCtx = OnceCell(() => this.uiCanvas().getContext('2d', {
+ protected uiCanvasCtx = OnceCell(() => this.uiCanvas.getContext('2d', {
alpha: true,
}))
protected drawUiCanvas() { }
@@ -138,44 +138,44 @@ export default class Video extends ThreeVideo {
case beat >= 13 && beat < 15: {
this.scene.background = new THREE.Color(0x000000);
- this.scene.add(this.lighting())
+ this.scene.add(this.lighting)
- this.scene.add(this.uiDark());
+ this.scene.add(this.uiDark);
const progress = (beat - 13) / 3.5
- this.uiDark().rotation.x = bezier(progress, 0.4, 0.6, 0.6, 1.1);
- this.uiDark().rotation.y = bezier(progress, 2, 1.7, 1.6, bezier(progress, 1, 0.8, 0.3, -0.5));
+ this.uiDark.rotation.x = bezier(progress, 0.4, 0.6, 0.6, 1.1);
+ this.uiDark.rotation.y = bezier(progress, 2, 1.7, 1.6, bezier(progress, 1, 0.8, 0.3, -0.5));
this.camera.position.z = bezier(progress, 6, 4, 4, bezier(progress, 7, 9, 15, 25));
- this.lighting().position.set(0, 0, this.camera.position.z);
+ this.lighting.position.set(0, 0, this.camera.position.z);
this.renderScene(this.ctx)
- this.scene.remove(this.uiDark());
- this.scene.remove(this.lighting())
+ this.scene.remove(this.uiDark);
+ this.scene.remove(this.lighting)
break;
}
case beat >= 15 && beat < 16: {
this.scene.background = new THREE.Color(0x000000);
- this.scene.add(this.lighting())
+ this.scene.add(this.lighting)
- this.scene.add(this.uiDark());
+ this.scene.add(this.uiDark);
const progress = (beat - 15)
- this.uiDark().rotation.x = bezier(progress, -0.5, -0.5, -0.5, -0.5);
- this.uiDark().rotation.y = bezier(progress, 0.7, 0.6, 0.4, 0.4);
+ this.uiDark.rotation.x = bezier(progress, -0.5, -0.5, -0.5, -0.5);
+ this.uiDark.rotation.y = bezier(progress, 0.7, 0.6, 0.4, 0.4);
this.camera.position.z = bezier(progress, 4, 5, 5, 8);
- this.lighting().position.set(-0.5, 0, this.camera.position.z);
+ this.lighting.position.set(-0.5, 0, this.camera.position.z);
this.renderScene(this.ctx)
- this.scene.remove(this.uiDark());
- this.scene.remove(this.lighting())
+ this.scene.remove(this.uiDark);
+ this.scene.remove(this.lighting)
break;
}
case beat >= 16 && beat < 18.4: {
- this.scene.add(this.uiLight());
+ this.scene.add(this.uiLight);
const progress = (beat - 16) / 3.5
- this.uiLight().rotation.x = bezier(progress, -0.5, 0.6, 0.6, 1.1) * (beat < 17 ? 1 : -1);
- this.uiLight().rotation.y = bezier(progress, 0.4, 1.7, 1.8, 2) * (beat < 17 ? 1 : -1);
+ this.uiLight.rotation.x = bezier(progress, -0.5, 0.6, 0.6, 1.1) * (beat < 17 ? 1 : -1);
+ this.uiLight.rotation.y = bezier(progress, 0.4, 1.7, 1.8, 2) * (beat < 17 ? 1 : -1);
this.camera.position.z = bezier(progress, 8, 4, 4, 12);
this.renderScene(this.ctx)
- this.scene.remove(this.uiLight());
+ this.scene.remove(this.uiLight);
break;
}
case beat >= 18.4 && beat < 22.8: {
@@ -247,7 +247,7 @@ export default class Video extends ThreeVideo {
renderText(this.ctx, `${(Math.floor(beat * 10) / 10).toFixed(1)}`, '#646663', { ...AdDefault, size: this.px(12), weight: 400 }, { x: this.w - this.px(4), y: this.h - this.px(4) }, 'end')
}
public cleanup(): void {
- this.uiCanvas().remove()
+ this.uiCanvas.remove()
super.cleanup()
}
public fps = 59.94;