diff --git a/client/src/features/visualizer-threejs/ConfigControls.scss b/client/src/features/visualizer-threejs/ConfigControls.scss index 44b1b5cf7..07da9d94d 100644 --- a/client/src/features/visualizer-threejs/ConfigControls.scss +++ b/client/src/features/visualizer-threejs/ConfigControls.scss @@ -19,9 +19,10 @@ color: var(--type-color); display: flex; gap: 8px; + flex-wrap: wrap; } .controls__item { - flex: 1; + width: 20%; display: flex; flex-direction: column; diff --git a/client/src/features/visualizer-threejs/ConfigControls.tsx b/client/src/features/visualizer-threejs/ConfigControls.tsx index fa9b6b29b..9a8da0a83 100644 --- a/client/src/features/visualizer-threejs/ConfigControls.tsx +++ b/client/src/features/visualizer-threejs/ConfigControls.tsx @@ -7,6 +7,7 @@ import { MIN_TILT_FACTOR_DEGREES, MAX_TILT_FACTOR_DEGREES, TILT_DURATION_SECONDS, + EMITTER_SPEED_MULTIPLIER, features, } from "./constants"; import { useTangleStore } from "~features/visualizer-threejs/store"; @@ -20,6 +21,7 @@ enum VisualizerConfig { MinTiltDegrees = "minTiltDegrees", MaxTiltDegrees = "maxTiltDegrees", TiltDurationSeconds = "tiltDurationSeconds", + EmitterSpeedMultiplier = "emitterSpeedMultiplier", } const VISUALIZER_CONFIG_LOCAL_STORAGE_KEY = "visualizerConfigs"; @@ -32,6 +34,7 @@ const DEFAULT_VISUALIZER_CONFIG_VALUES: Record = { [VisualizerConfig.MinTiltDegrees]: MIN_TILT_FACTOR_DEGREES, [VisualizerConfig.MaxTiltDegrees]: MAX_TILT_FACTOR_DEGREES, [VisualizerConfig.TiltDurationSeconds]: TILT_DURATION_SECONDS, + [VisualizerConfig.EmitterSpeedMultiplier]: EMITTER_SPEED_MULTIPLIER, }; /** @@ -125,6 +128,12 @@ export const ConfigControls = () => { min: 1, max: 100, }, + { + key: VisualizerConfig.EmitterSpeedMultiplier, + label: "Emitter Speed Multiplier", + min: 0, + max: 1000, + }, ]; const handleApply = () => { @@ -197,45 +206,51 @@ export const ConfigControls = () => { )} -
- - { - const input = e.target.value; - - if (!input) { - setLocalZoom(undefined); - return; - } - - const numberRegExp = /^-?\d+(\.|\.\d*|\d*)?$/; - if (numberRegExp.test(input)) { - if (input.endsWith(".")) { - setLocalZoom(input as any); - } else { - const value = parseFloat(input); - if (value > 2) { - setLocalZoom(2); - return; - } - setLocalZoom(value); - } - } - }} - /> -
- + /> + {!!errors["zoom"] &&
{errors["zoom"]}
} +
+ +
diff --git a/client/src/features/visualizer-threejs/store/tangle.ts b/client/src/features/visualizer-threejs/store/tangle.ts index 1f47b446b..0438608f5 100644 --- a/client/src/features/visualizer-threejs/store/tangle.ts +++ b/client/src/features/visualizer-threejs/store/tangle.ts @@ -1,10 +1,11 @@ import { Color } from "three"; import { create } from "zustand"; import { devtools } from "zustand/middleware"; -import { ZOOM_DEFAULT, EMITTER_SPEED_MULTIPLIER, SPRAY_DISTANCE } from "../constants"; +import { ZOOM_DEFAULT, SPRAY_DISTANCE } from "../constants"; import { IFeedBlockData } from "~models/api/nova/feed/IFeedBlockData"; import { IThreeDimensionalPosition } from "../interfaces"; import { BlockId, SlotIndex } from "@iota/sdk-wasm-nova/web"; +import { getVisualizerConfigValues } from "~features/visualizer-threejs/ConfigControls"; export interface IBlockAnimationPosition { initPosition: IThreeDimensionalPosition; @@ -107,8 +108,11 @@ export const useTangleStore = create()( state.blockIdToAnimationPosition.set(key, value); }); + const { emitterSpeedMultiplier } = getVisualizerConfigValues(); + for (const [key, value] of state.blockIdToAnimationPosition) { - const animationTime = SPRAY_DISTANCE / EMITTER_SPEED_MULTIPLIER; + // const animationTime = SPRAY_DISTANCE / emitterSpeedMultiplier; + const animationTime = SPRAY_DISTANCE / emitterSpeedMultiplier; if (value.elapsedTime > animationTime) { state.blockIdToAnimationPosition.delete(key); } diff --git a/client/src/features/visualizer-threejs/useRenderTangle.tsx b/client/src/features/visualizer-threejs/useRenderTangle.tsx index 4da8ff476..a9d5c107e 100644 --- a/client/src/features/visualizer-threejs/useRenderTangle.tsx +++ b/client/src/features/visualizer-threejs/useRenderTangle.tsx @@ -1,12 +1,13 @@ import { useThree } from "@react-three/fiber"; import { useEffect, useRef, useState } from "react"; import * as THREE from "three"; -import { SPRAY_ANIMATION_DURATION, MAX_BLOCK_INSTANCES, NODE_SIZE_DEFAULT } from "./constants"; +import { MAX_BLOCK_INSTANCES, NODE_SIZE_DEFAULT, SPRAY_DISTANCE } from "./constants"; import { useMouseMove } from "./hooks/useMouseMove"; import { IBlockState, IBlockAnimationPosition, useConfigStore, useTangleStore } from "./store"; import { useRenderEdges } from "./useRenderEdges"; import useVisualizerTimer from "~/helpers/nova/hooks/useVisualizerTimer"; import { positionToVector } from "./utils"; +import { getVisualizerConfigValues } from "~features/visualizer-threejs/ConfigControls"; const SPHERE_GEOMETRY = new THREE.SphereGeometry(NODE_SIZE_DEFAULT, 32, 16); const SPHERE_MATERIAL = new THREE.MeshPhongMaterial(); @@ -155,10 +156,12 @@ export const useRenderTangle = () => { const SPRAY_FRAMES_PER_SECOND = 24; const interval = setInterval(() => { + const { emitterSpeedMultiplier } = getVisualizerConfigValues(); blockIdToAnimationPosition.forEach((properties, blockId) => { const { initPosition, targetPosition, blockAddedTimestamp } = properties; const currentAnimationTime = getVisualizerTimeDiff(); const elapsedTime = currentAnimationTime - blockAddedTimestamp; + const SPRAY_ANIMATION_DURATION = SPRAY_DISTANCE / emitterSpeedMultiplier; const animationAlpha = Math.min(elapsedTime / SPRAY_ANIMATION_DURATION, 1); const targetPositionVector = new THREE.Vector3(); diff --git a/client/src/features/visualizer-threejs/utils.ts b/client/src/features/visualizer-threejs/utils.ts index 146ee5116..e687a51e5 100644 --- a/client/src/features/visualizer-threejs/utils.ts +++ b/client/src/features/visualizer-threejs/utils.ts @@ -5,7 +5,6 @@ import { MIN_TANGLE_RADIUS, MAX_TANGLE_RADIUS, MAX_BLOCK_INSTANCES, - EMITTER_SPEED_MULTIPLIER, CAMERA_X_AXIS_MOVEMENT, CAMERA_Y_AXIS_MOVEMENT, CAMERA_X_OFFSET, @@ -177,12 +176,12 @@ export function getTangleDistances(): { xTangleDistance: number; yTangleDistance: number; } { - const { maxSinusoidAmplitude } = getVisualizerConfigValues(); + const { maxSinusoidAmplitude, emitterSpeedMultiplier } = getVisualizerConfigValues(); /* We assume MAX BPS to get the max possible Y */ const MAX_TANGLE_DISTANCE_SECONDS = MAX_BLOCK_INSTANCES / MIN_BLOCKS_PER_SECOND; - const MAX_BLOCK_DISTANCE = EMITTER_SPEED_MULTIPLIER * MAX_TANGLE_DISTANCE_SECONDS; + const MAX_BLOCK_DISTANCE = emitterSpeedMultiplier * MAX_TANGLE_DISTANCE_SECONDS; const maxXDistance = MAX_BLOCK_DISTANCE; @@ -254,7 +253,8 @@ export function calculateSinusoidalAmplitude({ * @returns the emitter position */ export function calculateEmitterPositionX(currentAnimationTime: number): number { - return currentAnimationTime * EMITTER_SPEED_MULTIPLIER; + const { emitterSpeedMultiplier } = getVisualizerConfigValues(); + return currentAnimationTime * emitterSpeedMultiplier; } /**