From a930d0cf0ecddc6e7fb6fb8f6b9822a59b16496b Mon Sep 17 00:00:00 2001 From: Sean Boult <996134+Hacksore@users.noreply.github.com> Date: Sat, 16 Sep 2023 11:26:27 -0500 Subject: [PATCH] Format (#146) --- .prettierrc | 10 +++++ package-lock.json | 22 ++++++++++ package.json | 2 + src/animation.ts | 20 +++------ src/model.ts | 93 ++++++++++++++++++++++++++------------- src/nametag.ts | 16 ++++--- src/viewer.ts | 110 +++++++++++++++++++++++++--------------------- 7 files changed, 172 insertions(+), 101 deletions(-) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..cbc2020 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "trailingComma": "es5", + "tabWidth": 2, + "semi": true, + "printWidth": 120, + "singleQuote": false, + "quoteProps": "as-needed", + "arrowParens": "avoid", + "endOfLine": "auto" +} diff --git a/package-lock.json b/package-lock.json index 57389ee..ce7700e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "eslint-plugin-tsdoc": "^0.2.17", "local-web-server": "^5.2.1", "npm-run-all": "^4.1.5", + "prettier": "^3.0.3", "rimraf": "^3.0.2", "rollup": "^3.20.7", "rollup-plugin-swc3": "^0.8.1", @@ -3586,6 +3587,21 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -7205,6 +7221,12 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", diff --git a/package.json b/package.json index ca8e38e..0eadaaf 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "build:modules": "tsc -p .", "build:bundles": "rollup -c --configPlugin=swc3", "build": "npm run build:modules && npm run build:bundles", + "format": "prettier src --write", "test:lint": "eslint --ext .ts src", "test": "npm run test:lint", "dev:watch:modules": "tsc -w --preserveWatchOutput --declaration --sourceMap --outDir libs -p .", @@ -54,6 +55,7 @@ "eslint-plugin-tsdoc": "^0.2.17", "local-web-server": "^5.2.1", "npm-run-all": "^4.1.5", + "prettier": "^3.0.3", "rimraf": "^3.0.2", "rollup": "^3.20.7", "rollup-plugin-swc3": "^0.8.1", diff --git a/src/animation.ts b/src/animation.ts index f5640ae..6138b85 100644 --- a/src/animation.ts +++ b/src/animation.ts @@ -7,7 +7,6 @@ import { PlayerObject } from "./model.js"; * particular animations. */ export abstract class PlayerAnimation { - /** * The speed of the animation. * @@ -64,7 +63,6 @@ export abstract class PlayerAnimation { * ``` */ export class FunctionAnimation extends PlayerAnimation { - fn: (player: PlayerObject, progress: number, delta: number) => void; constructor(fn: (player: PlayerObject, progress: number, delta: number) => void) { @@ -78,7 +76,6 @@ export class FunctionAnimation extends PlayerAnimation { } export class IdleAnimation extends PlayerAnimation { - protected animate(player: PlayerObject): void { // Multiply by animation's natural speed const t = this.progress * 2; @@ -95,7 +92,6 @@ export class IdleAnimation extends PlayerAnimation { } export class WalkingAnimation extends PlayerAnimation { - /** * Whether to shake head when walking. * @@ -134,7 +130,6 @@ export class WalkingAnimation extends PlayerAnimation { } export class RunningAnimation extends PlayerAnimation { - protected animate(player: PlayerObject): void { // Multiply by animation's natural speed const t = this.progress * 15 + Math.PI * 0.5; @@ -173,7 +168,6 @@ function clamp(num: number, min: number, max: number): number { } export class FlyingAnimation extends PlayerAnimation { - protected animate(player: PlayerObject): void { // Body rotation finishes in 0.5s // Elytra expansion finishes in 3.3s @@ -181,18 +175,18 @@ export class FlyingAnimation extends PlayerAnimation { const t = this.progress > 0 ? this.progress * 20 : 0; const startProgress = clamp((t * t) / 100, 0, 1); - player.rotation.x = startProgress * Math.PI / 2; - player.skin.head.rotation.x = startProgress > .5 ? Math.PI / 4 - player.rotation.x : 0; + player.rotation.x = (startProgress * Math.PI) / 2; + player.skin.head.rotation.x = startProgress > 0.5 ? Math.PI / 4 - player.rotation.x : 0; - const basicArmRotationZ = Math.PI * .25 * startProgress; + const basicArmRotationZ = Math.PI * 0.25 * startProgress; player.skin.leftArm.rotation.z = basicArmRotationZ; player.skin.rightArm.rotation.z = -basicArmRotationZ; - const elytraRotationX = .34906584; + const elytraRotationX = 0.34906584; const elytraRotationZ = Math.PI / 2; - const interpolation = Math.pow(.9, t); - player.elytra.leftWing.rotation.x = elytraRotationX + interpolation * (.2617994 - elytraRotationX); - player.elytra.leftWing.rotation.z = elytraRotationZ + interpolation * (.2617994 - elytraRotationZ); + const interpolation = Math.pow(0.9, t); + player.elytra.leftWing.rotation.x = elytraRotationX + interpolation * (0.2617994 - elytraRotationX); + player.elytra.leftWing.rotation.z = elytraRotationZ + interpolation * (0.2617994 - elytraRotationZ); player.elytra.updateRightWing(); } } diff --git a/src/model.ts b/src/model.ts index 4ec3297..361cd35 100644 --- a/src/model.ts +++ b/src/model.ts @@ -1,12 +1,32 @@ import type { ModelType } from "skinview-utils"; -import { BoxGeometry, BufferAttribute, DoubleSide, FrontSide, Group, Mesh, MeshStandardMaterial, Object3D, Texture, Vector2 } from "three"; - -function setUVs(box: BoxGeometry, u: number, v: number, width: number, height: number, depth: number, textureWidth: number, textureHeight: number): void { +import { + BoxGeometry, + BufferAttribute, + DoubleSide, + FrontSide, + Group, + Mesh, + MeshStandardMaterial, + Object3D, + Texture, + Vector2, +} from "three"; + +function setUVs( + box: BoxGeometry, + u: number, + v: number, + width: number, + height: number, + depth: number, + textureWidth: number, + textureHeight: number +): void { const toFaceVertices = (x1: number, y1: number, x2: number, y2: number) => [ new Vector2(x1 / textureWidth, 1.0 - y2 / textureHeight), new Vector2(x2 / textureWidth, 1.0 - y2 / textureHeight), new Vector2(x2 / textureWidth, 1.0 - y1 / textureHeight), - new Vector2(x1 / textureWidth, 1.0 - y1 / textureHeight) + new Vector2(x1 / textureWidth, 1.0 - y1 / textureHeight), ]; const top = toFaceVertices(u + depth, v, u + width + depth, v + depth); @@ -18,12 +38,30 @@ function setUVs(box: BoxGeometry, u: number, v: number, width: number, height: n const uvAttr = box.attributes.uv as BufferAttribute; uvAttr.copyVector2sArray([ - right[3], right[2], right[0], right[1], - left[3], left[2], left[0], left[1], - top[3], top[2], top[0], top[1], - bottom[0], bottom[1], bottom[3], bottom[2], - front[3], front[2], front[0], front[1], - back[3], back[2], back[0], back[1] + right[3], + right[2], + right[0], + right[1], + left[3], + left[2], + left[0], + left[1], + top[3], + top[2], + top[0], + top[1], + bottom[0], + bottom[1], + bottom[3], + bottom[2], + front[3], + front[2], + front[0], + front[1], + back[3], + back[2], + back[0], + back[1], ]); uvAttr.needsUpdate = true; } @@ -51,7 +89,6 @@ export class BodyPart extends Group { } export class SkinObject extends Group { - // body parts readonly head: BodyPart; readonly body: BodyPart; @@ -73,12 +110,12 @@ export class SkinObject extends Group { super(); this.layer1Material = new MeshStandardMaterial({ - side: FrontSide + side: FrontSide, }); this.layer2Material = new MeshStandardMaterial({ side: DoubleSide, transparent: true, - alphaTest: 1e-5 + alphaTest: 1e-5, }); this.layer1MaterialBiased = this.layer1Material.clone(); @@ -144,7 +181,7 @@ export class SkinObject extends Group { const rightArmPivot = new Group(); rightArmPivot.add(rightArmMesh, rightArm2Mesh); this.modelListeners.push(() => { - rightArmPivot.position.x = this.slim ? -.5 : -1; + rightArmPivot.position.x = this.slim ? -0.5 : -1; }); rightArmPivot.position.y = -4; @@ -206,7 +243,7 @@ export class SkinObject extends Group { this.rightLeg.add(rightLegPivot); this.rightLeg.position.x = -1.9; this.rightLeg.position.y = -12; - this.rightLeg.position.z = -.1; + this.rightLeg.position.z = -0.1; this.add(this.rightLeg); // Left Leg @@ -227,7 +264,7 @@ export class SkinObject extends Group { this.leftLeg.add(leftLegPivot); this.leftLeg.position.x = 1.9; this.leftLeg.position.y = -12; - this.leftLeg.position.z = -.1; + this.leftLeg.position.z = -0.1; this.add(this.leftLeg); this.modelType = "default"; @@ -267,11 +304,11 @@ export class SkinObject extends Group { } setInnerLayerVisible(value: boolean): void { - this.getBodyParts().forEach(part => part.innerLayer.visible = value); + this.getBodyParts().forEach(part => (part.innerLayer.visible = value)); } setOuterLayerVisible(value: boolean): void { - this.getBodyParts().forEach(part => part.outerLayer.visible = value); + this.getBodyParts().forEach(part => (part.outerLayer.visible = value)); } resetJoints(): void { @@ -284,7 +321,6 @@ export class SkinObject extends Group { } export class CapeObject extends Group { - readonly cape: Mesh; private material: MeshStandardMaterial; @@ -295,7 +331,7 @@ export class CapeObject extends Group { this.material = new MeshStandardMaterial({ side: DoubleSide, transparent: true, - alphaTest: 1e-5 + alphaTest: 1e-5, }); // +z (front) - inside of cape @@ -304,7 +340,7 @@ export class CapeObject extends Group { setCapeUVs(capeBox, 0, 0, 10, 16, 1); this.cape = new Mesh(capeBox, this.material); this.cape.position.y = -8; - this.cape.position.z = .5; + this.cape.position.z = 0.5; this.add(this.cape); } @@ -319,7 +355,6 @@ export class CapeObject extends Group { } export class ElytraObject extends Group { - readonly leftWing: Group; readonly rightWing: Group; @@ -331,7 +366,7 @@ export class ElytraObject extends Group { this.material = new MeshStandardMaterial({ side: DoubleSide, transparent: true, - alphaTest: 1e-5 + alphaTest: 1e-5, }); const leftWingBox = new BoxGeometry(12, 22, 4); @@ -356,13 +391,13 @@ export class ElytraObject extends Group { this.add(this.rightWing); this.leftWing.position.x = 5; - this.leftWing.rotation.x = .2617994; + this.leftWing.rotation.x = 0.2617994; this.resetJoints(); } resetJoints(): void { - this.leftWing.rotation.y = .01; // to avoid z-fighting - this.leftWing.rotation.z = .2617994; + this.leftWing.rotation.y = 0.01; // to avoid z-fighting + this.leftWing.rotation.z = 0.2617994; this.updateRightWing(); } @@ -389,7 +424,6 @@ export class ElytraObject extends Group { } export class EarsObject extends Group { - readonly rightEar: Mesh; readonly leftEar: Mesh; @@ -399,7 +433,7 @@ export class EarsObject extends Group { super(); this.material = new MeshStandardMaterial({ - side: FrontSide + side: FrontSide, }); const earBox = new BoxGeometry(8, 8, 4 / 3); setUVs(earBox, 0, 0, 6, 6, 1, 14, 7); @@ -427,10 +461,9 @@ export class EarsObject extends Group { export type BackEquipment = "cape" | "elytra"; -const CapeDefaultAngle = 10.8 * Math.PI / 180; +const CapeDefaultAngle = (10.8 * Math.PI) / 180; export class PlayerObject extends Group { - readonly skin: SkinObject; readonly cape: CapeObject; readonly elytra: ElytraObject; diff --git a/src/nametag.ts b/src/nametag.ts index 45fb023..b651200 100644 --- a/src/nametag.ts +++ b/src/nametag.ts @@ -1,7 +1,6 @@ import { CanvasTexture, NearestFilter, Sprite, SpriteMaterial } from "three"; export interface NameTagOptions { - /** * A font specification using the CSS value syntax. * @@ -70,7 +69,6 @@ export interface NameTagOptions { * A Minecraft name tag, i.e. a text label with background. */ export class NameTagObject extends Sprite { - /** * A promise that is resolved after the name tag is fully painted. * @@ -97,7 +95,7 @@ export class NameTagObject extends Sprite { constructor(text: string = "", options: NameTagOptions = {}) { const material = new SpriteMaterial({ transparent: true, - alphaTest: 1e-5 + alphaTest: 1e-5, }); super(material); @@ -137,7 +135,8 @@ export class NameTagObject extends Sprite { // Compute canvas size canvas.width = this.margin[3] + metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight + this.margin[1]; - canvas.height = this.margin[0] + metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent + this.margin[2]; + canvas.height = + this.margin[0] + metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent + this.margin[2]; // After change canvas size, the context needs to be re-created // eslint-disable-next-line @typescript-eslint/no-non-null-assertion @@ -150,7 +149,11 @@ export class NameTagObject extends Sprite { // Draw text ctx.fillStyle = this.textStyle; - ctx.fillText(this.text, this.margin[3] + metrics.actualBoundingBoxLeft, this.margin[0] + metrics.actualBoundingBoxAscent); + ctx.fillText( + this.text, + this.margin[3] + metrics.actualBoundingBoxLeft, + this.margin[0] + metrics.actualBoundingBoxAscent + ); // Apply texture const texture = new CanvasTexture(canvas); @@ -160,8 +163,7 @@ export class NameTagObject extends Sprite { this.textMaterial.needsUpdate = true; // Update size - this.scale.x = canvas.width / canvas.height * this.height; + this.scale.x = (canvas.width / canvas.height) * this.height; this.scale.y = this.height; } - } diff --git a/src/viewer.ts b/src/viewer.ts index b1af2ef..b84516b 100644 --- a/src/viewer.ts +++ b/src/viewer.ts @@ -1,5 +1,36 @@ -import { inferModelType, isTextureSource, loadCapeToCanvas, loadEarsToCanvas, loadEarsToCanvasFromSkin, loadImage, loadSkinToCanvas, type ModelType, type RemoteImage, type TextureSource } from "skinview-utils"; -import { Color, type ColorRepresentation, PointLight, EquirectangularReflectionMapping, Group, NearestFilter, PerspectiveCamera, Scene, Texture, Vector2, WebGLRenderer, AmbientLight, Mapping, CanvasTexture, WebGLRenderTarget, FloatType, DepthTexture, Clock, Object3D } from "three"; +import { + inferModelType, + isTextureSource, + loadCapeToCanvas, + loadEarsToCanvas, + loadEarsToCanvasFromSkin, + loadImage, + loadSkinToCanvas, + type ModelType, + type RemoteImage, + type TextureSource, +} from "skinview-utils"; +import { + Color, + type ColorRepresentation, + PointLight, + EquirectangularReflectionMapping, + Group, + NearestFilter, + PerspectiveCamera, + Scene, + Texture, + Vector2, + WebGLRenderer, + AmbientLight, + Mapping, + CanvasTexture, + WebGLRenderTarget, + FloatType, + DepthTexture, + Clock, + Object3D, +} from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; import { EffectComposer, FullScreenQuad } from "three/examples/jsm/postprocessing/EffectComposer.js"; import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js"; @@ -10,18 +41,15 @@ import { type BackEquipment, PlayerObject } from "./model.js"; import { NameTagObject } from "./nametag.js"; export interface LoadOptions { - /** * Whether to make the object visible after the texture is loaded. * * @defaultValue `true` */ makeVisible?: boolean; - } export interface SkinLoadOptions extends LoadOptions { - /** * The model of the player (`"default"` for normal arms, and `"slim"` for slim arms). * @@ -42,11 +70,9 @@ export interface SkinLoadOptions extends LoadOptions { * @defaultValue `false` */ ears?: boolean | "load-only"; - } export interface CapeLoadOptions extends LoadOptions { - /** * The equipment (`"cape"` or `"elytra"`) to show when the cape texture is loaded. * @@ -55,11 +81,9 @@ export interface CapeLoadOptions extends LoadOptions { * @defaultValue `"cape"` */ backEquipment?: BackEquipment; - } export interface EarsLoadOptions extends LoadOptions { - /** * The type of the provided ear texture. * @@ -69,11 +93,9 @@ export interface EarsLoadOptions extends LoadOptions { * @defaultValue `"standalone"` */ textureType?: "standalone" | "skin"; - } export interface SkinViewerOptions { - /** * The canvas where the renderer draws its output. * @@ -138,10 +160,12 @@ export interface SkinViewerOptions { * * @defaultValue If unspecified, the ears will be invisible. */ - ears?: "current-skin" | { - textureType: "standalone" | "skin", - source: RemoteImage | TextureSource - } + ears?: + | "current-skin" + | { + textureType: "standalone" | "skin"; + source: RemoteImage | TextureSource; + }; /** * Whether to preserve the buffers until manually cleared or overwritten. @@ -226,7 +250,6 @@ export interface SkinViewerOptions { * The SkinViewer renders the player on a canvas. */ export class SkinViewer { - /** * The canvas where the renderer draws its output. */ @@ -318,7 +341,7 @@ export class SkinViewer { this.renderer = new WebGLRenderer({ canvas: this.canvas, - preserveDrawingBuffer: options.preserveDrawingBuffer === true // default: false + preserveDrawingBuffer: options.preserveDrawingBuffer === true, // default: false }); this.onDevicePixelRatioChange = () => { @@ -348,7 +371,7 @@ export class SkinViewer { // Use float precision depth if possible // see https://github.com/bs-community/skinview3d/issues/111 renderTarget = new WebGLRenderTarget(0, 0, { - depthTexture: new DepthTexture(0, 0, FloatType) + depthTexture: new DepthTexture(0, 0, FloatType), }); } this.composer = new EffectComposer(this.renderer, renderTarget); @@ -377,7 +400,7 @@ export class SkinViewer { if (options.skin !== undefined) { this.loadSkin(options.skin, { model: options.model, - ears: options.ears === "current-skin" + ears: options.ears === "current-skin", }); } if (options.cape !== undefined) { @@ -385,7 +408,7 @@ export class SkinViewer { } if (options.ears !== undefined && options.ears !== "current-skin") { this.loadEars(options.ears.source, { - textureType: options.ears.textureType + textureType: options.ears.textureType, }); } if (options.width !== undefined) { @@ -481,13 +504,9 @@ export class SkinViewer { options?: SkinLoadOptions ): S extends TextureSource ? void : Promise; - loadSkin( - source: TextureSource | RemoteImage | null, - options: SkinLoadOptions = {} - ): void | Promise { + loadSkin(source: TextureSource | RemoteImage | null, options: SkinLoadOptions = {}): void | Promise { if (source === null) { this.resetSkin(); - } else if (isTextureSource(source)) { loadSkinToCanvas(this.skinCanvas, source); this.recreateSkinTexture(); @@ -509,7 +528,6 @@ export class SkinViewer { this.playerObject.ears.visible = true; } } - } else { return loadImage(source).then(image => this.loadSkin(image, options)); } @@ -530,13 +548,9 @@ export class SkinViewer { options?: CapeLoadOptions ): S extends TextureSource ? void : Promise; - loadCape( - source: TextureSource | RemoteImage | null, - options: CapeLoadOptions = {} - ): void | Promise { + loadCape(source: TextureSource | RemoteImage | null, options: CapeLoadOptions = {}): void | Promise { if (source === null) { this.resetCape(); - } else if (isTextureSource(source)) { loadCapeToCanvas(this.capeCanvas, source); this.recreateCapeTexture(); @@ -544,7 +558,6 @@ export class SkinViewer { if (options.makeVisible !== false) { this.playerObject.backEquipment = options.backEquipment === undefined ? "cape" : options.backEquipment; } - } else { return loadImage(source).then(image => this.loadCape(image, options)); } @@ -566,13 +579,9 @@ export class SkinViewer { options?: EarsLoadOptions ): S extends TextureSource ? void : Promise; - loadEars( - source: TextureSource | RemoteImage | null, - options: EarsLoadOptions = {} - ): void | Promise { + loadEars(source: TextureSource | RemoteImage | null, options: EarsLoadOptions = {}): void | Promise { if (source === null) { this.resetEars(); - } else if (isTextureSource(source)) { if (options.textureType === "skin") { loadEarsToCanvasFromSkin(this.earsCanvas, source); @@ -584,7 +593,6 @@ export class SkinViewer { if (options.makeVisible !== false) { this.playerObject.ears.visible = true; } - } else { return loadImage(source).then(image => this.loadEars(image, options)); } @@ -599,9 +607,7 @@ export class SkinViewer { } } - loadPanorama( - source: S - ): S extends TextureSource ? void : Promise { + loadPanorama(source: S): S extends TextureSource ? void : Promise { return this.loadBackground(source, EquirectangularReflectionMapping); } @@ -610,10 +616,7 @@ export class SkinViewer { mapping?: Mapping ): S extends TextureSource ? void : Promise; - loadBackground( - source: S, - mapping?: Mapping - ): void | Promise { + loadBackground(source: S, mapping?: Mapping): void | Promise { if (isTextureSource(source)) { if (this.backgroundTexture !== null) { this.backgroundTexture.dispose(); @@ -631,7 +634,7 @@ export class SkinViewer { } private draw(): void { - const dt = this.clock.getDelta() + const dt = this.clock.getDelta(); if (this._animation !== null) { this._animation.update(this.playerObject, dt); } @@ -644,9 +647,9 @@ export class SkinViewer { } /** - * Renders the scene to the canvas. - * This method does not change the animation progress. - */ + * Renders the scene to the canvas. + * This method does not change the animation progress. + */ render(): void { this.composer.render(); } @@ -704,7 +707,12 @@ export class SkinViewer { this.animationID = null; this.clock.stop(); this.clock.autoStart = true; - } else if (!this._renderPaused && !this._disposed && !this.renderer.getContext().isContextLost() && this.animationID == null) { + } else if ( + !this._renderPaused && + !this._disposed && + !this.renderer.getContext().isContextLost() && + this.animationID == null + ) { this.animationID = window.requestAnimationFrame(() => this.draw()); } } @@ -742,7 +750,7 @@ export class SkinViewer { } adjustCameraDistance(): void { - let distance = 4.5 + 16.5 / Math.tan(this.fov / 180 * Math.PI / 2) / this.zoom; + let distance = 4.5 + 16.5 / Math.tan(((this.fov / 180) * Math.PI) / 2) / this.zoom; // limit distance between 10 ~ 256 (default min / max distance of OrbitControls) if (distance < 10) {