diff --git a/dist/bundle.js b/dist/bundle.js index 3912198..5c693b0 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -16,7 +16,7 @@ \*********************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { -eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst THREE = __webpack_require__(/*! three */ \"./node_modules/three/build/three.cjs\");\nclass SphereWithRods {\n constructor() {\n this.rods = [];\n this.totalDuration = 60; // seconds\n this.animate = () => {\n requestAnimationFrame(this.animate);\n const orbitSpeed = 0.00025;\n const time = Date.now() * orbitSpeed;\n this.camera.position.x = 5 * Math.sin(time);\n this.camera.position.y = 0;\n this.camera.position.z = 5 * Math.cos(time);\n this.camera.lookAt(new THREE.Vector3(0, 0, 0));\n this.renderer.render(this.scene, this.camera);\n };\n this.constructSphere();\n this.constructSparkline();\n this.addEventListeners();\n }\n addEventListeners() {\n window.addEventListener('resize', this.onWindowResize.bind(this), false);\n }\n onWindowResize() {\n // Update camera aspect ratio and renderer size\n this.camera.aspect = window.innerWidth / window.innerHeight;\n this.camera.updateProjectionMatrix();\n this.renderer.setSize(window.innerWidth, window.innerHeight);\n }\n constructSphere() {\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(0x0a0a0a); // Dark grey\n this.camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 100);\n this.renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });\n this.renderer.setSize(window.innerWidth, window.innerHeight);\n document.body.appendChild(this.renderer.domElement);\n this.camera.position.set(5, 5, 5);\n this.camera.lookAt(this.scene.position);\n this.rodMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.5 });\n this.startPlacingRods();\n this.animate();\n }\n constructSparkline() {\n this.sparklineCanvas = document.getElementById('sparkline-canvas');\n this.sparklineContext = this.sparklineCanvas.getContext('2d');\n this.startTime = Date.now();\n this.drawSparkline();\n }\n drawSparkline() {\n const currentTime = Date.now();\n const elapsedTime = (currentTime - this.startTime) / 1000; // in seconds\n const cycle = elapsedTime % (2 * this.totalDuration); // Complete cycle for back and forth\n const progress = (cycle > this.totalDuration) ? 2 - cycle / this.totalDuration : cycle / this.totalDuration;\n this.sparklineContext.clearRect(0, 0, this.sparklineCanvas.width, this.sparklineCanvas.height);\n this.sparklineContext.beginPath();\n // placing this slightly inside the canvas, to ensure that the line is not cut off\n for (let x = 10; x <= this.sparklineCanvas.width - 20; x++) {\n const t = x / this.sparklineCanvas.width;\n const y = this.calculateFrequency(t) * (this.sparklineCanvas.height - 20) + 10;\n this.sparklineContext.lineTo(x, this.sparklineCanvas.height - y);\n }\n this.sparklineContext.stroke();\n // placing this slightly inside the canvas, to ensure that the line is not cut off\n const lineX = progress * (this.sparklineCanvas.width - 20) + 10;\n this.sparklineContext.beginPath();\n this.sparklineContext.moveTo(lineX, 0);\n this.sparklineContext.lineTo(lineX, this.sparklineCanvas.height);\n this.sparklineContext.strokeStyle = 'white';\n this.sparklineContext.lineWidth = 2;\n this.sparklineContext.stroke();\n requestAnimationFrame(this.drawSparkline.bind(this));\n }\n calculateFrequency(t) {\n // Sine function adjusted for [0, 1] range, peaking in the middle\n const sineWave = Math.sin(Math.PI * t);\n // Raise the sine wave to a power to make the curve more dramatic\n const power = 20; // Adjust this power to make the curve more or less dramatic\n const dramaticSineWave = Math.pow(sineWave, power);\n return dramaticSineWave;\n }\n placeRod() {\n // Base length and maximum length of the rods\n const baseLength = 1; // Assuming R = 1 for simplicity\n const maxLength = 4; // 4R\n const biasFactor = 3; // Adjust this value to control the bias; higher values favor shorter rods more\n // Generate a biased random length\n // Math.pow(Math.random(), biasFactor) generates a number between 0 and 1, skewed towards 0\n // Multiplying by (maxLength - baseLength) scales it to the desired range\n // Adding baseLength offsets it so the minimum is baseLength, not 0\n const rodLength = baseLength + Math.pow(Math.random(), biasFactor) * (maxLength - baseLength);\n // Rod geometry\n const rodGeometry = new THREE.CylinderGeometry(0.01, 0.01, rodLength, 32);\n const rod = new THREE.Mesh(rodGeometry, this.rodMaterial);\n // Random spherical coordinates\n const phi = Math.random() * 2 * Math.PI; // Azimuthal angle\n const theta = Math.acos(2 * Math.random() - 1); // Polar angle, adjusted for uniform distribution\n const jitter = 0.9 + Math.random() * 0.2; // Jitter for radius (0.9 to 1.1)\n // Convert spherical to Cartesian coordinates for position\n const x = jitter * Math.sin(theta) * Math.cos(phi);\n const y = jitter * Math.sin(theta) * Math.sin(phi);\n const z = jitter * Math.cos(theta);\n // Set rod position\n rod.position.set(x, y, z);\n // Create a vector representing the rod's position\n const rodPosition = new THREE.Vector3(x, y, z);\n // Calculate the radial direction from the sphere's center to the rod's position\n const radialDirection = rodPosition.clone().normalize();\n // Calculate the up direction for the rod (tangent to the sphere at the rod's position)\n // This can be any vector that is not parallel to the radial direction\n // Here, we use a simple trick: if the radial direction is not vertical, use the world up direction; otherwise, use the world forward direction\n const upDirection = Math.abs(radialDirection.y) < 0.99 ? new THREE.Vector3(0, 1, 0) : new THREE.Vector3(0, 0, 1);\n // Calculate the tangent direction at the rod's position by taking the cross product of the radial and up directions\n const tangentDirection = new THREE.Vector3().crossVectors(radialDirection, upDirection).normalize();\n // Rotate the rod to align with the tangent direction\n rod.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), tangentDirection);\n // Apply an additional random rotation around the radial direction to vary the orientation of the rods\n const randomAngle = Math.random() * 2 * Math.PI; // Random angle for rotation\n rod.rotateOnWorldAxis(radialDirection, randomAngle); // Rotate the rod around the radial direction by the random angle\n // Add the rod to the scene and the rods array\n this.scene.add(rod);\n this.rods.push(rod);\n }\n startPlacingRods() {\n const placeOrRemoveRod = () => {\n const elapsedTime = (Date.now() - this.startTime) / 1000; // in seconds\n const cycle = Math.floor(elapsedTime / this.totalDuration);\n const t = (elapsedTime % this.totalDuration) / this.totalDuration; // Normalized time for current half-cycle\n const frequency = this.calculateFrequency(t);\n const delayFactor = Math.pow(1 - frequency, 4); // Adjust the exponent as needed\n const delay = 1000 - (1000 - 25) * (1 - delayFactor);\n if (cycle % 2 === 0) {\n this.placeRod(); // Add rod during even cycles\n }\n else if (this.rods.length > 0) {\n const removeIndex = Math.floor(Math.random() * this.rods.length);\n const [removedRod] = this.rods.splice(removeIndex, 1); // Remove random rod during odd cycles\n this.scene.remove(removedRod);\n }\n setTimeout(placeOrRemoveRod, delay);\n };\n placeOrRemoveRod();\n }\n}\nnew SphereWithRods();\n\n\n//# sourceURL=webpack://flow/./src/main.ts?"); +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst THREE = __webpack_require__(/*! three */ \"./node_modules/three/build/three.cjs\");\nclass SphereWithRods {\n constructor() {\n this.rods = [];\n this.totalDuration = 5; // seconds\n this.animate = () => {\n requestAnimationFrame(this.animate);\n const orbitSpeed = 0.00025;\n const time = Date.now() * orbitSpeed;\n this.camera.position.x = 5 * Math.sin(time);\n this.camera.position.y = 0;\n this.camera.position.z = 5 * Math.cos(time);\n this.camera.lookAt(new THREE.Vector3(0, 0, 0));\n this.renderer.render(this.scene, this.camera);\n };\n this.constructSphere();\n this.constructSparkline();\n this.addEventListeners();\n }\n addEventListeners() {\n window.addEventListener('resize', this.onWindowResize.bind(this), false);\n }\n onWindowResize() {\n // Update camera aspect ratio and renderer size\n this.camera.aspect = window.innerWidth / window.innerHeight;\n this.camera.updateProjectionMatrix();\n this.renderer.setSize(window.innerWidth, window.innerHeight);\n }\n constructSphere() {\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(0x0a0a0a); // Dark grey\n this.camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 100);\n this.renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });\n this.renderer.setSize(window.innerWidth, window.innerHeight);\n document.body.appendChild(this.renderer.domElement);\n this.camera.position.set(5, 5, 5);\n this.camera.lookAt(this.scene.position);\n this.rodMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.5 });\n this.startPlacingRods();\n this.animate();\n }\n constructSparkline() {\n this.sparklineCanvas = document.getElementById('sparkline-canvas');\n this.sparklineContext = this.sparklineCanvas.getContext('2d');\n this.startTime = Date.now();\n this.drawSparkline();\n }\n drawSparkline() {\n const currentTime = Date.now();\n const elapsedTime = (currentTime - this.startTime) / 1000; // in seconds\n const cycle = elapsedTime % (2 * this.totalDuration); // Complete cycle for back and forth\n const progress = (cycle > this.totalDuration) ? 2 - cycle / this.totalDuration : cycle / this.totalDuration;\n this.sparklineContext.clearRect(0, 0, this.sparklineCanvas.width, this.sparklineCanvas.height);\n this.sparklineContext.beginPath();\n // placing this slightly inside the canvas, to ensure that the line is not cut off\n for (let x = 10; x <= this.sparklineCanvas.width - 10; x++) {\n const t = x / this.sparklineCanvas.width;\n const y = this.calculateFrequency(t) * (this.sparklineCanvas.height - 20) + 10;\n this.sparklineContext.lineTo(x, this.sparklineCanvas.height - y);\n }\n this.sparklineContext.stroke();\n // placing this slightly inside the canvas, to ensure that the line is not cut off\n const lineX = progress * (this.sparklineCanvas.width - 20) + 10;\n this.sparklineContext.beginPath();\n this.sparklineContext.moveTo(lineX, 0);\n this.sparklineContext.lineTo(lineX, this.sparklineCanvas.height);\n this.sparklineContext.strokeStyle = 'white';\n this.sparklineContext.lineWidth = 2;\n this.sparklineContext.stroke();\n requestAnimationFrame(this.drawSparkline.bind(this));\n }\n calculateFrequency(t) {\n // Sine function adjusted for [0, 1] range, peaking in the middle\n const sineWave = Math.sin(Math.PI * t);\n // Raise the sine wave to a power to make the curve more dramatic\n const power = 20; // Adjust this power to make the curve more or less dramatic\n const dramaticSineWave = Math.pow(sineWave, power);\n return dramaticSineWave;\n }\n placeRod() {\n // Base length and maximum length of the rods\n const baseLength = 1; // Assuming R = 1 for simplicity\n const maxLength = 4; // 4R\n const biasFactor = 3; // Adjust this value to control the bias; higher values favor shorter rods more\n // Generate a biased random length\n // Math.pow(Math.random(), biasFactor) generates a number between 0 and 1, skewed towards 0\n // Multiplying by (maxLength - baseLength) scales it to the desired range\n // Adding baseLength offsets it so the minimum is baseLength, not 0\n const rodLength = baseLength + Math.pow(Math.random(), biasFactor) * (maxLength - baseLength);\n // Rod geometry\n const rodGeometry = new THREE.CylinderGeometry(0.01, 0.01, rodLength, 32);\n const rod = new THREE.Mesh(rodGeometry, this.rodMaterial);\n // Random spherical coordinates\n const phi = Math.random() * 2 * Math.PI; // Azimuthal angle\n const theta = Math.acos(2 * Math.random() - 1); // Polar angle, adjusted for uniform distribution\n const jitter = 0.9 + Math.random() * 0.2; // Jitter for radius (0.9 to 1.1)\n // Convert spherical to Cartesian coordinates for position\n const x = jitter * Math.sin(theta) * Math.cos(phi);\n const y = jitter * Math.sin(theta) * Math.sin(phi);\n const z = jitter * Math.cos(theta);\n // Set rod position\n rod.position.set(x, y, z);\n // Create a vector representing the rod's position\n const rodPosition = new THREE.Vector3(x, y, z);\n // Calculate the radial direction from the sphere's center to the rod's position\n const radialDirection = rodPosition.clone().normalize();\n // Calculate the up direction for the rod (tangent to the sphere at the rod's position)\n // This can be any vector that is not parallel to the radial direction\n // Here, we use a simple trick: if the radial direction is not vertical, use the world up direction; otherwise, use the world forward direction\n const upDirection = Math.abs(radialDirection.y) < 0.99 ? new THREE.Vector3(0, 1, 0) : new THREE.Vector3(0, 0, 1);\n // Calculate the tangent direction at the rod's position by taking the cross product of the radial and up directions\n const tangentDirection = new THREE.Vector3().crossVectors(radialDirection, upDirection).normalize();\n // Rotate the rod to align with the tangent direction\n rod.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), tangentDirection);\n // Apply an additional random rotation around the radial direction to vary the orientation of the rods\n const randomAngle = Math.random() * 2 * Math.PI; // Random angle for rotation\n rod.rotateOnWorldAxis(radialDirection, randomAngle); // Rotate the rod around the radial direction by the random angle\n // Add the rod to the scene and the rods array\n this.scene.add(rod);\n this.rods.push(rod);\n }\n startPlacingRods() {\n const placeOrRemoveRod = () => {\n const elapsedTime = (Date.now() - this.startTime) / 1000; // in seconds\n const cycle = Math.floor(elapsedTime / this.totalDuration);\n const t = (elapsedTime % this.totalDuration) / this.totalDuration; // Normalized time for current half-cycle\n const frequency = this.calculateFrequency(t);\n const delayFactor = Math.pow(1 - frequency, 4); // Adjust the exponent as needed\n const delay = 1000 - (1000 - 25) * (1 - delayFactor);\n if (cycle % 2 === 0) {\n this.placeRod(); // Add rod during even cycles\n }\n else if (this.rods.length > 0) {\n const removeIndex = Math.floor(Math.random() * this.rods.length);\n const [removedRod] = this.rods.splice(removeIndex, 1); // Remove random rod during odd cycles\n this.scene.remove(removedRod);\n }\n setTimeout(placeOrRemoveRod, delay);\n };\n placeOrRemoveRod();\n }\n}\nnew SphereWithRods();\n\n\n//# sourceURL=webpack://flow/./src/main.ts?"); /***/ }), diff --git a/src/main.ts b/src/main.ts index b7ff8f6..f66ce68 100644 --- a/src/main.ts +++ b/src/main.ts @@ -9,7 +9,7 @@ class SphereWithRods { sparklineCanvas: HTMLCanvasElement; sparklineContext: CanvasRenderingContext2D; startTime: number; - totalDuration: number = 60; // seconds + totalDuration: number = 5; // seconds constructor() { this.constructSphere(); @@ -63,7 +63,7 @@ class SphereWithRods { this.sparklineContext.beginPath(); // placing this slightly inside the canvas, to ensure that the line is not cut off - for (let x = 10; x <= this.sparklineCanvas.width - 20; x++) { + for (let x = 10; x <= this.sparklineCanvas.width - 10; x++) { const t = x / this.sparklineCanvas.width; const y = this.calculateFrequency(t) * (this.sparklineCanvas.height - 20) + 10; this.sparklineContext.lineTo(x, this.sparklineCanvas.height - y);