The overhead of maintaining Wordpress was a bit too much for us, and the cost of hosting was high considering how quiet the website was.
To reduce complexity I want to set them up with a static site generator and have that export to GitLab. This will reduce cost and remove the hassle around security and of constantly logging in to update plugins etc.
But one issue I can't figure out is how they will get help when I'm not around. With something hosted completely on the server they could go to upwork.com and hire someone if the website had issues. When it's all local on their computer, how can someone from Upwork help them while maintaining the integrity of their local installation?
Anyone know how I can turn off this "heavy scroll" effect some websites have? Here's an example:
I just realized this might also be called a parallax effect, but I am not sure here. I'm basically looking for some javascript I could inject to take over an event handler method, or some CSS. I've tried overwriting scroll effects on some other sites but haven't had much success, so I'm wondering if anyone knows of a surefire way (aside from disabling JavaScript altogether)
My requirements are thus:
-
Works offline
-
Code is not obfuscated, does not have tons of added dependencies and libraries. I'm trying to speed up codewriting, not replace it completely.
-
Is not a virus
-
Generates files which can be hosted anywhere.
Unfortunately that seems to disqualify pretty much everything I've been able to find with a regular search engine. It would be nice, wouldn't it? To just have a photo-editor like program to throw a layout together, a list of divs and content, and another panel showing all the properties where you can set pixels or percentages, lock it in for non-flexible or leave it auto adjusting. Have them inherit properties from like a custom composition.
im working on a javascript UI framework for personal projects and im trying to create something like a React-hook that handles "encrypted at rest".
the react-hook is described in more detail here. id like to extend its functionality to have encrypted persistant data. my approach is the following and it would be great if you could follow along and let me know if im doing something wrong. all advice is apprciated.
im using indexedDB to store the data. i created some basic functionality to automatically persist and rehydrate data. im now investigating password-encrypting the data with javascript using the browser cryptography api.
i have a PR here you can test out on codespaces or clone, but tldr: i encrypt before saving and decrypt when loading. this seems to be working as expected. i will also encrypt/decrypt the event listeners im using and this should keep it safe from anything like browser extensions from listening to events.
the password is something the user will have to put in themselves at part of some init() process. i havent created an input for this yet, so its hardcoded. this is then used to encrypt/decrypt the data.
i would persist the unencrypted salt to indexedDB because this is then used to generate the key.
i think i am almost done with this functionality, but id like advice on anything ive overlooked or things too keep-in-mind. id like to make the storage as secure as possible.
Hello,
I would like to share a video tutorial on how to integrate a Large Language Model for FREE in Wordpress. Let me know what you think.
Cheers,
cross-posted from: https://lemm.ee/post/46067136
I'm designing a webapp that is supposed to be an AR environment on your phone, to be viewed with something like Google Cardboard, but I am having an issue that the segmentPointer object that is meant to appear when clicking on an object is not.
I've checked the geometry displays correctly in a sandbox, and when I change it to a 3d object rather than shapeGeometry it does display, but I cannot figure out why it is not displaying how I want it to.
The project is at https://voxelverse.jackgreenearth.org, and the code is quite long, but it is here to read in its totality below as it might need the whole context to discover the error. I've tried myself looking through the code, and I've tried searching the web and asking LLMs, but I couldn't figure it out, so please help me, fellow humans.
Tap for code
"use strict"; import \* as THREE from 'three'; import {GLTFLoader} from 'three/addons/loaders/GLTFLoader.js'; \ const loader = new GLTFLoader(); const textureLoader = new THREE.TextureLoader(); const manager = THREE.DefaultLoadingManager; \ // Basic functions \ function ls(id) { return(localStorage.getItem(id)); }; \ function setLs(id, val) { localStorage.setItem(id, val); }; \ function byId(id) { return(document.getElementById(id)); }; \ function bySel(sel) { return(document.querySelector(sel)); }; \ function byClass(id) { return(document.getElementsByClassName(id)); }; \ function toTitleCase(str) { return str.replace( /\w\S\*/g, function(txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); } ); }; \ function randInt(max) { return Math.floor(Math.random() \* (max)); }; \ function getRandomFloat(min, max, decimals) { return(parseFloat((Math.random() \* (max - min) + min).toFixed(decimals))); }; \ function confine(value, min, max) { if(value < min) { return(min); } else if(value > max) { return(max); } else { return(value); }; }; \ function wrap(value, min, max) { const range = max - min; \ if(value < min) { return(wrap(value + range, min, max)); } else if(value > max) { return(wrap(value - range, min, max)); } else { return(value); }; }; \ function removeFromArray(array, forDeletion) { return(array.filter(item => !forDeletion.includes(item))); }; \ function radToDeg(radians) { return radians \* (180 / PI); } \ function range(start, stop, step = 1) { if (stop === undefined) { stop = start; start = 0 } return Array.from({ length: (stop - start) / step }, (\_, i) => start + (i \* step)); } \ function between(variable, min, max, inclusive='min') { switch(inclusive) { case 'none': return((variable > min) && (variable < max)); break; case 'both': return((variable >= min) && (variable <= max)); break; case 'min': return((variable >= min) && (variable < max)); break; case 'max': return((variable > min) && (variable <= max)); break; } } \ function download(data, filename, type) { var file = new Blob(\[data], {type: type}); if (window\.navigator.msSaveOrOpenBlob) // IE10+ window\.navigator.msSaveOrOpenBlob(file, filename); else { // Others var a = document.createElement("a"), url = URL.createObjectURL(file); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); setTimeout(function() { document.body.removeChild(a); window\.URL.revokeObjectURL(url); }, 0); }; }; \ function log(text) { console.log(text); }; \ function distance2d(x1, y1, x2, y2) { return(Math.sqrt( (Math.abs(x1 - x2) \*\* 2) + (Math.abs(y1 - y2) \*\* 2) )); }; \ function distance3d(p1 = new THREE.Vector3(0, 0, 0), p2 = new THREE.Vector3(0, 0, 0)) { return(Math.sqrt((distance2d(p1.x, p1.y, p2.x, p2.y) \*\* 2) + (Math.abs(p1.z - p2.z) \*\* 2))); }; \ let totalElementsToLoad = 0; let numberOfElementsLoaded = 0; \ function onAllElementsLoaded() { \ } \ function load(path, type, functionOnLoad) { totalElementsToLoad += 1; \ if(type == 'html') { fetch(path) .then(response => response.text()) .then(html => { let doc = new DOMParser().parseFromString(html, "text/html"); \ functionOnLoad(doc); \ // If all elements to load have been loaded, execute the relevant function numberOfElementsLoaded += 1; if(numberOfElementsLoaded == totalElementsToLoad) { onAllElementsLoaded(); } }) .catch(error => { console.error(error); }); } else if(type == 'json') { fetch(path) .then(response => response.json()) // parse the response as JSON .then(json => { functionOnLoad(json); \ // If all elements to load have been loaded, execute the relevant function numberOfElementsLoaded += 1; if(numberOfElementsLoaded == totalElementsToLoad) { onAllElementsLoaded(); } }) .catch(error => { console.error(error); }); } } \ // Setup \ const PI = 3.1415926535897932384626433832795028841971; \ // Objects \ let orientation = { 'absolute': false, 'alpha': 0, 'beta': 0, 'gamma': 0 } \ // vars const fps = 60; \ let keysDown = \[]; let pointerPosition = {'x': 0, 'y': 0, 'positions': \[{'clientX': 0, 'clientY': 0}], 'type': 'mouse'}; \ // Camera let cameraRotation = new THREE.Euler(0, 0, 0, 'YXZ'); let cameraTargetRotation = {'x': 0, 'y': 0, 'z': 0}; const cameraRotationSensitivity = 0.002; \ // Other variables let logicInterval; \ // Load default settings let defaultSettings; \ load("/assets/json/default-settings.json", 'json', function(defset) { defaultSettings = defset; \ // Create custom settings if(!Object.keys(localStorage).includes('settings')) { setLs('settings', JSON.stringify({})); }; \ onSettingsLoad(); }); \ function settingURL(url, addValue=true) { return('children/' + url.split('/').join('/children/') + (addValue ? '/value' : '')); } \ function customiseSetting(url, value) { url = settingURL(url).split('/'); \ let newSettings; \ function recursiveSet(object, list, index, setTo) { // If the current component is the last one, assign the value if(index == list.length - 1) { object\[list\[index]] = setTo; return(object); } else { // Check if it already contains the value if(object.hasOwnProperty(list\[index])) { object\[list\[index]] = recursiveSet(object\[list\[index]], list, index + 1, setTo); } else { object\[list\[index]] = recursiveSet({}, list, index + 1, setTo); } return(object); } }; \ newSettings = recursiveSet(JSON.parse(ls('settings')), url, 0, value); \ setLs('settings', JSON.stringify(newSettings)); } \ function getSetting(url, addValue) { url = settingURL(url, addValue).split('/'); \ function recursiveGet(object, list, index) { // If the current component is the last one, return the value if (index == list.length - 1) { return object\[list\[index]]; } else { // Check if it contains the value if (object.hasOwnProperty(list\[index])) { return recursiveGet(object\[list\[index]], list, index + 1); } else { return null; // No such setting } } } \ // Try to find it in local settings first, otherwise get it from defaultSettings const localGet = recursiveGet(JSON.parse(ls('settings')), url, 0); if(localGet == null) { return(recursiveGet(defaultSettings, url, 0)); } else { return(localGet); } } \ // First, lets define some functions // Rendering functions \ // Thanks, https\://discourse.threejs.org/t/roundedrectangle-squircle/28645! function roundRectangleGeometry(w, h, r, s) { // width, height, radius corner, smoothness // helper const's const wi = w / 2 - r; // inner width const hi = h / 2 - r; // inner height const w2 = w / 2; // half width const h2 = h / 2; // half height const ul = r / w; // u left const ur = ( w - r ) / w; // u right const vl = r / h; // v low const vh = ( h - r ) / h; // v high let positions = \[ -wi, -h2, 0, wi, -h2, 0, wi, h2, 0, -wi, -h2, 0, wi, h2, 0, -wi, h2, 0, -w2, -hi, 0, -wi, -hi, 0, -wi, hi, 0, -w2, -hi, 0, -wi, hi, 0, -w2, hi, 0, wi, -hi, 0, w2, -hi, 0, w2, hi, 0, wi, -hi, 0, w2, hi, 0, wi, hi, 0 ]; let uvs = \[ ul, 0, ur, 0, ur, 1, ul, 0, ur, 1, ul, 1, 0, vl, ul, vl, ul, vh, 0, vl, ul, vh, 0, vh, ur, vl, 1, vl, 1, vh, ur, vl, 1, vh, ur, vh ]; let phia = 0; let phib, xc, yc, uc, vc, cosa, sina, cosb, sinb; for (let i = 0; i < s \* 4; i ++) { phib = Math.PI \* 2 \* ( i + 1 ) / ( 4 \* s ); cosa = Math.cos( phia ); sina = Math.sin( phia ); cosb = Math.cos( phib ); sinb = Math.sin( phib ); xc = i < s || i >= 3 \* s ? wi : - wi; yc = i < 2 \* s ? hi : -hi; positions.push( xc, yc, 0, xc + r \* cosa, yc + r \* sina, 0, xc + r \* cosb, yc + r \* sinb, 0 ); uc = i < s || i >= 3 \* s ? ur : ul; vc = i < 2 \* s ? vh : vl; uvs.push( uc, vc, uc + ul \* cosa, vc + vl \* sina, uc + ul \* cosb, vc + vl \* sinb ); phia = phib; } const geometry = new THREE.BufferGeometry( ); geometry.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( positions ), 3 ) ); geometry.setAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( uvs ), 2 ) ); return geometry; } \ // Render function render() { requestAnimationFrame(render); leftRenderer.render(scene, leftCamera); rightRenderer.render(scene, rightCamera); \ framesSoFar++; }; \ // Functions function setCameraRotation() { // Calculate drag cameraRotation.x = Number((cameraRotation.x + ((cameraTargetRotation.x - cameraRotation.x) / getSetting('Input/Mouse/Camera Rotation Drag'))).toFixed(5)); cameraRotation.y = Number((cameraRotation.y + ((cameraTargetRotation.y - cameraRotation.y) / getSetting('Input/Mouse/Camera Rotation Drag'))).toFixed(5)); cameraRotation.z = Number((cameraRotation.z + ((cameraTargetRotation.z - cameraRotation.z) / getSetting('Input/Mouse/Camera Rotation Drag'))).toFixed(5)); // Update cameras for(let camera of \[leftCamera, rightCamera]) { camera.rotation.set(cameraRotation.x, cameraRotation.y, cameraRotation.z, 'YXZ'); } \ const eyeGap = getSetting('Quick Settings/Eye Gap'); \ // Set camera positions leftCamera.position.x = -1 \* eyeGap \* Math.sin(cameraRotation.y); leftCamera.position.z = -1 \* eyeGap \* Math.cos(cameraRotation.y); rightCamera.position.x = eyeGap \* Math.sin(cameraRotation.y); rightCamera.position.z = eyeGap \* Math.cos(cameraRotation.y); \ byId('camera-target-rot-x').innerHTML = cameraTargetRotation.x.toFixed(2); byId('camera-target-rot-y').innerHTML = cameraTargetRotation.y.toFixed(2); byId('camera-target-rot-z').innerHTML = cameraTargetRotation.z.toFixed(2); byId('camera-rot-x').innerHTML = cameraRotation.x.toFixed(2); byId('camera-rot-y').innerHTML = cameraRotation.y.toFixed(2); byId('camera-rot-z').innerHTML = cameraRotation.z.toFixed(2); \ byId('camera-left-rot-x').innerHTML = leftCamera.rotation.x.toFixed(2); byId('camera-left-rot-y').innerHTML = leftCamera.rotation.y.toFixed(2); byId('camera-left-rot-z').innerHTML = leftCamera.rotation.z.toFixed(2); } \ function takeScreenshot() { downloadCanvasImage(document.getElementById('game-canvas'), gameName + ' screenshot'); sendAlert('Screenshot Taken!', 'tick'); }; \ function takePanorama() { const canvas = document.getElementById('game-canvas'); const height = canvas.height; const width = canvas.width \* (360 / (camera.fov \* camera.aspect)); let newCanvas = document.createElement('canvas'); newCanvas.height = height; newCanvas.width = width; newCanvas.style.display = 'none'; let context = newCanvas.getContext("2d"); document.body.appendChild(newCanvas); for(let x = 0; x < width; x++) { // Rotate cameraRotation.y += ((2 \* PI) / width); let calculatedRotation = rotationToAbsolute(playerPosition, cameraRotation); camera.rotation.set(calculatedRotation.x, calculatedRotation.y, calculatedRotation.z, 'YXZ'); renderer.render(scene, camera); const gl = renderer.getContext(); // Get canvas data const pixelData = new Uint8ClampedArray(1 \* height \* 4); const reversedPixelData = new Uint8ClampedArray(1 \* height \* 4); gl.readPixels((canvas.width / 2), 0, 1, height, gl.RGBA, gl.UNSIGNED\_BYTE, pixelData); for (let i = 0; i < height; i++) { for (let j = 0; j < 4; j++) { reversedPixelData\[i\*4 + j] = pixelData\[(height - i - 1)\*4 + j]; }; }; const imageData = new ImageData(reversedPixelData, 1, height); context.putImageData(imageData, x, 0); }; downloadCanvasImage(newCanvas, gameName + ' panorama'); newCanvas.remove(); sendAlert('Panoramic screenshot taken!', 'tick'); }; \ function setRotation(object, rotation) { object.rotation.set(rotation.x, rotation.y, rotation.z); }; \ function downloadCanvasImage(canvas, name) { let canvasImage = canvas.toDataURL('image/png'); // this can be used to download any image from webpage to local disk let xhr = new XMLHttpRequest(); xhr.responseType = 'blob'; xhr.onload = function () { let a = document.createElement('a'); a.href = window\.URL.createObjectURL(xhr.response); a.download = name; a.style.display = 'none'; document.body.appendChild(a); a.click(); a.remove(); }; xhr.open('GET', canvasImage); // This is to download the canvas image xhr.send(); }; \ function xyToRealPosRot(x, y, distance) { let realX, realY, realZ, rotX, rotY, rotZ; \ // Position is an object {x: x, y: y} x determines which face it will be on horizontally, and y determines if it will be on the top or the bottom // Beyond 400, x position wraps x = wrap(x, 0, 400); log('x before: ' + x) const horizontalFace = (x / 100) % 4; //rotY = (x / 400) \* (1) // horizontalFace); \ // The top of the screen is y 100, the bottom is y -100, and the horizontals are between -50 and 50 realY = confine(y, -100, 100); \ // Calculate real position const unit = getSetting('Display/UI/Distance') / 50; \ let forward = getSetting('Display/UI/Distance'); \ const bevel = getSetting('Display/UI/Bevel'); \ rotX = 0; \ // If it is horizontal... if(between(y, -50 + bevel, 50 - bevel)) { realY = y; rotX = 0; } else if(y < -50 - bevel) { // If it is on the lower face realY = -50; forward = (y + 100) \* unit; rotX = -(PI / 2); } else if(y >= 50 + bevel) { // If it is on the upper face realY = 50; forward = (y - 100) \* unit; //side = unit \* (((x - 50) % 100) + 50); rotX = (PI / 2); } else if(between(y, -50 - bevel, -50 + bevel)) { // If it is on the lower bevel realY = -50 - ((y + 50) / 2); rotX = (PI / 4); } else if(between(y, 50 - bevel, 50 + bevel)) { // If it is on the upper bevel realY = 50 + ((y - 50) / 2) ; rotX = -(PI / 4); } \ realY = realY \* unit; \ let flip = false; \ /\*if( (horizontalFace >= 0 && horizontalFace < 0.5) || (horizontalFace >= 1.5 && horizontalFace < 2.5) || (horizontalFace >= 3.5 && horizontalFace < 4) ) { flip = true; }\*/ \ let angle = (x / 400) \* (PI \* 2); realX = Math.sin(angle) \* forward; realZ = Math.cos(angle) \* forward; rotY = angle; log('rot y: ' + rotY) \ log({ 'x': realX, 'y': realY, 'forward': forward, }) \ // Take distance into account realX \*= distance; realY \*= distance; realZ \*= distance; \ return({ 'position': new THREE.Vector3(realX, realY, realZ), 'rotation': new THREE.Euler(rotX, rotY, rotZ, 'YXZ'), 'flip': flip }); } \ function addWidget({ name = '', position = {'x': 0, 'y': 0}, rotation = {'x': 0, 'y': 0, 'z': 0}, distance = 1, size = {'x': 10, 'y': 10}, radius = 3, shape = 'rRect', background = '#000000', opacity, textStyle = { 'align': 'center', 'weight': 0, // Range is 0 to 10 'font': 'DINRoundPro,arial,sans-serif', 'color': '#b0b0b0', 'vertical-align': 'center', 'font-size': 1 // Uses the same sizing system as the rest of the UI, so one unit of text is also one unit of object }, textContent = '', onclick = function() {}, onlongpress = function() {}, onhover = function() {}, onhoverexit = function() {}, ontruehover = function() {} }) { const realPosRot = xyToRealPosRot(position.x, position.y, distance); log(realPosRot) const realPos = realPosRot.position; let realRot = realPosRot.rotation; \ realRot.x += rotation.x; realRot.y += rotation.y; realRot.z = rotation.z; \ // Calculate real size const unit = getSetting('Display/UI/Distance') / 100; \ let width = unit \* size.x; let height = unit \* size.y; radius \*= unit; const scale = getSetting('Display/UI/Scale/General'); width \*= scale; height \*= scale; radius \*= scale; \ // Set mesh geometry let geometry; switch(shape) { case 'rRect': geometry = roundRectangleGeometry(width, height, radius, 10); break; case 'rect': geometry = new THREE.PlaneGeometry(width, height); break; case 'circle': geometry = new THREE.CircleGeometry((width + height) / 2, 32); break; } let material; \ if(opacity == undefined) { opacity = 1; } \ if(textContent == '') { if(background\[0] == '/') { loadTexture(background, function(texture) { material = new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide, opacity: opacity, transparent: true }); onTextureLoad(material); }) } else { material = new THREE.MeshBasicMaterial({ color: background, side: THREE.DoubleSide, opacity: opacity, transparent: true }); onTextureLoad(material); } } else { function prepareText(canvas) { // Proceed to prepare the canvas with the text ctx.font = \`${textStyle\["font-size"]}em ${textStyle\["font"]}\`; ctx.textAlign = textStyle\["align"]; ctx.fillStyle = textStyle\["color"]; ctx.fillText(textContent, 0, 0); // Compose the text onto the background const composedTexture = new THREE.CanvasTexture(canvas); \ // Generate the material material = new THREE.MeshBasicMaterial({ map: composedTexture, side: THREE.DoubleSide, transparent: true, alphaTest: 0.5 }); \ onTextureLoad(material); } \ // Initialize tmpcanvas only when needed const tmpcanvas = document.createElement('canvas'); tmpcanvas.width = width; tmpcanvas.height = height; const ctx = tmpcanvas.getContext('2d'); \ \ // Fill the background first if (background\[0] == '/') { loadTexture(background, function(texture) { ctx.fillStyle = texture; ctx.fillRect(0, 0, width, height); \ prepareText(tmpcanvas); }) } else { ctx.fillStyle = background; ctx.fillRect(0, 0, width, height); \ prepareText(tmpcanvas); } } function onTextureLoad(material) { // Create a mesh with the geometry and the material let mesh = new THREE.Mesh(geometry, material); \ mesh.name = name; \ mesh.position.set(realPos.x, realPos.y, realPos.z ); mesh.rotation.set(realRot.x, realRot.y, realRot.z); \ if(realPosRot.flip) { mesh.scale.x = -1; } \ mesh.onclick = onclick; mesh.onlongpress = onlongpress; mesh.onhoverexit = onhoverexit; mesh.ontruehover = ontruehover; mesh.onchover = onhover; \ scene.add(mesh); }; } \ function transitionWidget(name, property, newProperty, time, condition) { if(condition != null) { } } \ // three.js Scene setup const scene = new THREE.Scene(); \ // three functions \ function loadTexture(path, onload) { textureLoader.load(path, function (texture) { onload(texture); }, undefined, function (error) { console.error(error); }); }; \ // Define objects to make them global, they will mostly be only added to the scene when settings are loaded let sun; let wallpaper; let cameraStream; let pointer; \ let pointerMaterial = new THREE.MeshBasicMaterial({ color: "hsl(0, 100%, 50%)", side: THREE.DoubleSide }); \ let segmentShape = new THREE.Shape(); let segmentGeometry = new THREE.ShapeGeometry(segmentShape); let segmentPointer = new THREE.Mesh(segmentGeometry, pointerMaterial); segmentPointer.name = 'segmentPointer'; \ function setSegmentPointer(angle = 0, radius = 0.1, rotation = new THREE.Euler(0, 0, 0), clockwise=true) { let oldGeometry = segmentPointer.geometry; \ let segmentShape = new THREE.Shape(); segmentShape.moveTo(0, 0); segmentShape.arc(0, 0, radius, 0, angle, clockwise); segmentShape.lineTo(0, 0); \ let extrudeSettings = { steps: 1, depth: 0.1, bevelEnabled: false }; \ let segmentGeometry = new THREE.ExtrudeGeometry(segmentShape, extrudeSettings); segmentPointer.geometry = segmentGeometry; \ oldGeometry.dispose(); \ segmentPointer.rotation.set(rotation); } \ // Camera stuff let cameraViewDistance; \ // Setup cameras let leftCamera; let rightCamera; let leftRenderer; let rightRenderer; \ function setRendererSize() { for(let renderer of \[leftRenderer, rightRenderer]) { let canvas = renderer.domElement; renderer.setSize( canvas.offsetWidth \* getSetting('Display/Anti-alias'), canvas.offsetHeight \* getSetting('Display/Anti-alias'), false ); } } \ function updateCameraAspectRatio() {-0.2 for(let camera of \[leftCamera, rightCamera]) { let canvas = leftRenderer.domElement; camera.aspect = canvas.offsetWidth / canvas.offsetHeight; camera.updateProjectionMatrix(); } } \ // temp function startAssistant() { log('assisstant') } \ // When settings are loaded, start settings stuff up function onSettingsLoad() { // Add sun sun = new THREE.PointLight(0xffffff, getSetting('Quick Settings/Brightness')); scene.add(sun); \ // Pointers pointer = new THREE.Mesh(new THREE.IcosahedronGeometry(getSetting('Display/UI/Pointer/Size'), 1), pointerMaterial); pointer.name = 'pointer'; scene.add(pointer); \ pointerMaterial = new THREE.MeshBasicMaterial( {color: "hsl(" + (getSetting('Quick Settings/Theme Hue') + getSetting('Display/UI/Pointer/Hue Shift')) + ", 100%, 50%)"} ); pointer.material = pointerMaterial; segmentPointer.material = pointerMaterial; \ // Add wallpaper let wallpaperURL; if(getSetting('Display/UI/Wallpaper/Use Direct Link') == true) { wallpaperURL = getSetting('Display/UI/Wallpaper/Direct Link'); } else { wallpaperURL = getSetting('Display/UI/Wallpaper/Wallpapers Folder') + '/' + getSetting('Display/UI/Wallpaper/Wallpaper'); } \ loadTexture(wallpaperURL, function(texture) { let material = new THREE.MeshStandardMaterial({ map: texture, side: THREE.BackSide, transparent: true, opacity: getSetting('Display/UI/Wallpaper/Opacity') }); \ wallpaper = new THREE.Mesh( new THREE.IcosahedronGeometry( getSetting('Display/UI/Distance') \* getSetting('Display/UI/Wallpaper/Distance') \* getSetting('Display/UI/Testing Size Multiplier'), 4), material ); wallpaper.scale.x = -1; wallpaper.name = "wallpaper"; scene.add(wallpaper); }); \ // Setup cameras cameraViewDistance = getSetting('Display/UI/Distance') \* getSetting('Display/UI/Testing Size Multiplier') \* 2; // Keep this down to destroy lag leftCamera = new THREE.PerspectiveCamera(80, 1, 0.001, cameraViewDistance); rightCamera = new THREE.PerspectiveCamera(80, 1, 0.001, cameraViewDistance); \ // Setup renderers leftRenderer = new THREE.WebGLRenderer({canvas: byId('left-canvas'), antialias: true, logarithmicDepthBuffer: true, preserveDrawingBuffer: true, alpha: true}); rightRenderer = new THREE.WebGLRenderer({canvas: byId('right-canvas'), antialias: true, logarithmicDepthBuffer: true, preserveDrawingBuffer: true, alpha: true}); \ updateCameraAspectRatio(); setRendererSize(); \ window\.addEventListener('resize', function() { updateCameraAspectRatio(); setRendererSize(); }); \ // Setup control center const baseY = getSetting('Display/Control Center/Switch To Bottom') ? -100 : 100; const backgroundFolder = getSetting('Display/Control Center/Icon Folder'); function createTileGrid(scale, x, y, farness, tiles, name) { let counter = 0; log(tiles) addWidget({ position: {'x': x, 'y': baseY + y}, size: {'x': 3 \* scale, 'y': 3 \* scale}, background: "hsl(" + getSetting('Quick Settings/Theme Hue') + ", 50%, 80%)", name: name + ' background', radius: 0.5 \* scale, onhover: openTileGroup(name) }); for(let widgetY = 1; widgetY >= -1; widgetY--) { for(let widgetX = -1; widgetX <=1; widgetX++) { if(counter < tiles.length) { if(tiles\[counter].folder) { createTileGrid(scale / 3, (widgetX \* scale), (widgetY \* scale), farness \* 0.99, tiles\[counter].children); } else { log('scale' + scale) addWidget({ position: {'x': x + (widgetX \* scale), 'y': baseY + y + (widgetY \* scale)}, size: {'x': scale, 'y': scale}, background: backgroundFolder + '/' + tiles\[counter].icon + '.svg', name: tiles\[counter].name, group: name, radius: scale / 3, distance: farness \* 0.99 }); log('added widget control center') }; } else { break; }; counter++; }; if(counter >= tiles.length) { break; }; }; }; \ createTileGrid( getSetting('Display/UI/Scale/Control Center') \* 1.5, 0, baseY, 1, getSetting('Display/Control Center/Tiles'), getSetting('Display/Control Center/Tiles', false)\['name'] ); // Quick function let quickFunction = getSetting('Display/Control Center/Quick Function', false); \ addWidget({ position: {'x': 0, 'y': getSetting('Display/Control Center/Switch To Bottom') ? 100 : -100}, background: '/assets/images/icons/control\_center/' + quickFunction.icon + '.svg', name: quickFunction.name, onclick: quickFunction.onclick }); \ // testing addWidget({ position: {'x': 0, 'y': -50}, background: '/assets/images/icons/control\_center/torch.svg', name: "torch" }); addWidget({ position: {'x': 200, 'y': 10}, background: '/assets/images/icons/control\_center/screencast.svg', name: "screencast" }); for(let i of range(16)) { addWidget({ position: {'x': i \* 25, 'y': 0}, background: 'hsl(' + getSetting('Quick Settings/Theme Hue') + ', 100%, ' + ((i / 16) \* 100) + '%)', name: "test" + i, textContent: '',//i.toString() 'onclick': function() { log('click' + i); }, 'onhover': function() { log('hover' + i); } }); } }; \ function updateSetting(url, value) { customiseSetting(url, value); \ switch(url) { case 'Display/UI/Wallpaper/Opacity': wallpaper.material.opacity = value; break; }; }; \ // Start \ // Setup the camera stream function setupCameraStream() { function handleSuccess(stream) { cameraStream = document.createElement('video'); cameraStream.style.transform = 'rotate(270deg)'; cameraStream.srcObject = stream; cameraStream.play(); \ let texture = new THREE.VideoTexture(cameraStream); texture.minFilter = THREE.LinearFilter; texture.magFilter = THREE.LinearFilter; scene.background = texture; \ customiseSetting('Display/UI/Wallpaper/Opacity', 0); // Temporary until GUI settings are introduced } \ function handleError(error) { // Set wallpaper opacity to 1 updateSetting('Display/UI/Wallpaper/Opacity', 1); \ log('Unable to access the camera/webcam.'); } \ navigator.mediaDevices.getUserMedia({video: {facingMode: "environment"}}) .then(handleSuccess) .catch(function(error) { if (error.name === 'OverconstrainedError') { // Fallback to default video settings navigator.mediaDevices.getUserMedia({video: true}) .then(handleSuccess) .catch(handleError); } else { // Handle other errors handleError(error); } }); }; \ // Fullscreen and pointer lock, request fullscreen mode for the element function openFullscreen(elem, then) { if (elem.requestFullscreen) { elem.requestFullscreen().then(then); } else if (elem.webkitRequestFullscreen) { /\* Safari \*/ elem.webkitRequestFullscreen().then(then); } else if (elem.msRequestFullscreen) { /\* IE11 \*/ elem.msRequestFullscreen().then(then); } } // Request pointer lock function requestPointerLock(myTargetElement) { const promise = myTargetElement.requestPointerLock({ unadjustedMovement: true, }); \ if (!promise) { log("disabling mouse acceleration is not supported"); return; } \ return promise .then(() => log("pointer is locked")) .catch((error) => { if (error.name === "NotSupportedError") { // Some platforms may not support unadjusted movement. // You can request again a regular pointer lock. return myTargetElement.requestPointerLock(); } }); } \ function lockPointer() { requestPointerLock(byId('body')); document.addEventListener("pointerlockchange", lockChangeAlert, false); }; \ function lockChangeAlert() { if (document.pointerLockElement === byId('body')) { document.addEventListener("mousemove", updatePosition, false); } else { document.removeEventListener("mousemove", updatePosition, false); } } \ function updatePosition(e) { onLockedMouseMove(e.movementX, e.movementY); }; \ function fullscreenAndPointerLock() { openFullscreen(byId('body'), function() { lockPointer(); }); } \ function permission() { // Check if the device supports deviceorientation and requestPermission if (typeof(DeviceMotionEvent) !== "undefined" && typeof(DeviceMotionEvent.requestPermission) === "function") { // Request permission DeviceMotionEvent.requestPermission() .then(response => { // Check the response if (response == "granted") {}; }) .catch(console.error); // Handle errors } else { // Device does not support deviceorientation log("DeviceOrientationEvent is not defined"); } } \ async function keepScreenAwake() { // Create a reference for the Wake Lock. let wakeLock = null; \ // create an async function to request a wake lock try { wakeLock = await navigator.wakeLock.request("screen"); log("Wake Lock is active!"); } catch (err) { // The Wake Lock request has failed - usually system related, such as battery. log(\`${err.name}, ${err.message}\`); } } \ let framesSoFar = 0; \ function startFPSCount() { byId('logic-fps').innerHTML = fps.toString(); \ let renderFPSInterval = setInterval(function() { byId('render-fps').innerHTML = framesSoFar.toString(); framesSoFar = 0; }, 1000); } \ function start() { byId('loading-screen').style.display = 'none'; setupCameraStream(); startLogic(); startFPSCount(); render(); permission(); fullscreenAndPointerLock(); keepScreenAwake(); \ byId('left-canvas').addEventListener('click', fullscreenAndPointerLock); byId('right-canvas').addEventListener('click', fullscreenAndPointerLock); }; \ // Loading byId('loading-bar').style.display = 'block'; \ manager.onProgress = function (url, itemsLoaded, itemsTotal) { //log('Loading file: ' + url + '.\nLoaded ' + itemsLoaded + ' of ' + itemsTotal + ' files.'); \ byId('loading-bar-fg').style.setProperty('--size', ((itemsLoaded / itemsTotal) \* 100) + '%'); }; \ manager.onError = function (url) { log('There was an error loading ' + url); }; \ manager.onLoad = function ( ) { setTimeout(function() { byId('loading-bar').style.display = 'none'; byId('play').style.display = 'block'; }, 500); byId('play').addEventListener('click', start); }; \ function openTileGroup(group) { } \ // Logic let pointerRaycast = new THREE.Raycaster(); let previousIntersection = pointerRaycast.intersectObjects(scene.children); let clicking = false; \ function logic() { // Set camera rotation if(cameraTargetRotation.x != cameraRotation.x || cameraTargetRotation.y != cameraRotation.y) { setCameraRotation(); }; \ // Update pointer pointerRaycast.set( new THREE.Vector3(0, 0, 0), leftCamera.getWorldDirection(new THREE.Vector3()) ); \ // Check if the pointer is itersecting with any object \ const intersections = pointerRaycast.intersectObjects(scene.children); if (intersections.length > 0) { for(let intersection of intersections) { // If it's intersecting with itself, don't do anything if(intersection.object.name == 'pointer' || intersection.object.name == 'segmentPointer') { return; } else { // If it's intersecting with an object, copy that intersection's position, and start to click const point = intersections\[0].point; pointer.position.copy(point); \ // Truehover if(Object.keys(intersection.object).includes('ontruehover')) { // Prevent hover being continuously trigggered if(previousIntersection.uuid != intersections\[0].uuid) { intersection.object.ontruehover(); } } log('truehover') \ // Start click after grace period, if object is clickable if( Object.keys(intersection.object).includes('onclick') || Object.keys(intersection.object).includes('onhover') || Object.keys(intersection.object).includes('onhoverexit') || Object.keys(intersection.object).includes('onlongpress') ) { let gracePeriod = setTimeout(function() { // onhover if(Object.keys(intersection.object).includes('onhover')) { intersection.object.onhover(); } log('hover') \ // Start click if(Object.keys(intersection.object).includes('onclick') && (!clicking)) { clicking = true; \ let fullness = 0; \ // Manage pointers scene.add(segmentPointer); segmentPointer.position.copy(pointer); scene.remove(pointer); let startClick = setInterval(function() { fullness += (PI \* 2) / (fps \* getSetting('Input/Eye Click/Duration/Pre-click duration')); setSegmentPointer( fullness, getSetting('Display/UI/Pointer/Size') \* getSetting('Display/UI/Pointer/Clicking Size'), intersection.object.rotation ); \ byId('pointer-angle').innerHTML = fullness.toFixed(4); \ // On forfeit let forfeitDistance = distance3d(point, pointerRaycast.intersectObjects(scene.children)\[0].point); if(forfeitDistance > getSetting('Input/Eye Click/Movement limit')) { log('forfeit ' + forfeitDistance) clearInterval(startClick); afterClick(); } \ if(fullness >= PI \* 2) { log('click') intersection.object.onclick(); clearInterval(startClick); \ if(Object.keys(intersection.object).includes('onlongpress')) { // Start longpress fullness = 0; let startLongPress = setInterval(function() { fullness += (PI \* 2) / (fps \* getSetting('Input/Eye Click/Duration/Long-press duration')); setSegmentPointer( fullness, getSetting('Display/UI/Pointer/Size') \* getSetting('Display/UI/Pointer/Clicking Size'), intersection.object.rotation, false ); byId('pointer-angle').innerHTML = fullness.toFixed(4); \ let forfeitDistance = distance3d(point, pointerRaycast.intersectObjects(scene.children)\[0].point); if(forfeitDistance > getSetting('Input/Eye Click/Movement limit')) { log('forfeitlongpress') clearInterval(startLongPress); afterClick(); }; \ // On click if(fullness >= PI \* 2) { intersection.object.onlongpress(); log('longpress') clearInterval(startLongPress); afterClick(); } }, 1000 / fps); } else { afterClick(); } } }, 1000 / fps); }; }, getSetting('Input/Eye Click/Delayed hover duration') \* 1000) return; } else { afterClick(); } \ function afterClick() { // Update previous intersection previousIntersection = intersections; previousIntersection.intersection = intersection; \ // Onhoverexit if(intersection.object.uuid != previousIntersection.intersection.object.uuid) { previousIntersection.object.onhoverexit(); } \ clicking = false; log('afterclick') \ // Change back pointers scene.remove(segmentPointer); scene.add(pointer); \ return; } } } }; }; \ function startLogic() { logicInterval = setInterval(logic, 1000 / fps); }; \ function stopLogic() { clearInterval(logicInterval); cameraStream.pause(); }; \ // Input function onLockedMouseMove(xMotion, yMotion) { cameraTargetRotation.x = confine(cameraTargetRotation.x - (yMotion \* cameraRotationSensitivity), -0.5 \* PI, 0.6 \* PI); if(wrap(cameraTargetRotation.y - (xMotion \* cameraRotationSensitivity), -PI, PI) != (cameraTargetRotation.y - (xMotion \* cameraRotationSensitivity))) { cameraRotation.y = wrap(cameraTargetRotation.y - (xMotion \* cameraRotationSensitivity), -PI, PI); }; cameraTargetRotation.y = wrap(cameraTargetRotation.y - (xMotion \* cameraRotationSensitivity), -PI, PI); setCameraRotation(); }; \ // Setup buttons byId('toggle-debug').addEventListener('click', function(event) { if(byId('debug-menu').style.display == 'block') { byId('debug-menu').style.display = 'none'; } else { byId('debug-menu').style.display = 'block'; } }); \ // Keypress manager const keysToPreventDefault = \['alt', '/', 'f1', 'f2', 'f3']; \ function putKeyDown(key) { if(!keysDown.includes(key.toLowerCase())) { keysDown.push(key.toLowerCase()); }; }; \ function putKeyUp(key) { keysDown = removeFromArray(keysDown, \[key.toLowerCase()]); }; \ document.addEventListener('keydown', function(e) { if(keysToPreventDefault.includes(e.key.toLowerCase())) { e.preventDefault(); }; putKeyDown(e.key); }); \ document.addEventListener('keyup', function(e) { putKeyUp(e.key); }); \ // Pointer position document.addEventListener('mousemove', function(e) { pointerPosition = {'x': e.clientX, 'y': e.clientY, 'positions': \[{'clientX': e.clientX, 'clientY': e.clientY}], 'type': 'mouse'}; }); \ document.addEventListener('touchmove', function(e) { pointerPosition = {'x': e.touches\[0].clientX, 'y': e.touches\[0].clientY, 'positions': e.touches, 'type': 'touch'}; }); \ // Gyrometer window\.addEventListener("deviceorientation", function(event) { orientation = { 'absolute': event.absolute, 'alpha': event.alpha, 'beta': event.beta, 'gamma': event.gamma }; \ byId('gyro-absolute').innerHTML = orientation.absolute; byId('gyro-alpha').innerHTML = orientation.alpha.toFixed(2); byId('gyro-beta').innerHTML = orientation.beta.toFixed(2); byId('gyro-gamma').innerHTML = orientation.gamma.toFixed(2); const theOrientation = (window\.offsetWidth > window\.offsetHeight) ? 'landscape' : 'portrait'; \ // If orientation is logged correctly if(!Object.values(orientation).includes(null)) { // Subtract 90deg if in portrait mode if(theOrientation == 'portrait') { orientation.alpha = wrap(orientation.alpha + 90, 0, 360); } \ // Offset y const offsetY = 89.5; // I have no idea why this works \ if(Math.abs(orientation.beta) < 100) { cameraTargetRotation.x = (-orientation.gamma \* (PI / 180) % 180) - offsetY; } else { cameraTargetRotation.x = (orientation.gamma \* (PI / 180) % 180) + offsetY; } cameraTargetRotation.y = orientation.alpha \* (PI / 180); cameraTargetRotation.z = (-orientation.beta \* (PI / 180)) + offsetY; \ cameraRotation.x = cameraTargetRotation.x; cameraRotation.y = cameraTargetRotation.y; cameraRotation.z = cameraTargetRotation.z; \ if(theOrientation == 'landscape') { } \ setCameraRotation(); }; }, true);
cross-posted from: https://feddit.nl/post/22255240
What a funny intro! ๐
Deno is a modern JavaScript/TypeScript runtime built by the creator of Node.js, designed as a more secure and developer-friendly alternative. Unlike Node, Deno runs with strict permissions (no file, network, or environment access by default) and includes TypeScript support out of the box. It also natively supports modern web APIs and provides built-in utilities like testing and formatting, reducing the need for external dependencies. Plus, itโs modular, offering direct URL-based imports instead of relying on
node_modules
.
Hi everyone, I have an old gaming PC that I had repurposed to be my nextcloud and plex server using TrueNAS, but I recently found CasaOS and I would like to migrate my server to use this instead. What are some best practices that I should observe when installing a different OS into a server? My server is installed on an M.2 drive and I have two 1TB HDD setup in raid.
Whenever I launch a new web project I go to Google Search Console and Bing Webmaster Tools to flag that the new website exists. The idea is to start getting SEO seniority / attention as early as possible.
Is there any other tool I should be registering my website in, or are these the major two?
Crossposted from https://lemmy.world/post/19723787
My Gitlab Pages site works well under domain.com but not under www.domain.com. The www subdomain leads to a 401 message: "You don't have permission to access the resource."
My DNS has a CNAME entry for www pointing to domain.com. When I asked the DNS provider what the problem might be they said "Please contact your hosting provider and provide us with the record needed to be set for www in the DNS zone. The changes should have worked already."
The reason I need this is that some old-school people visiting our website still type www. into the URL bar.
In which I explain how a freelance gig was born out of a sincere friendship, and how the website went through idea, process, implementation and delivery.
https://github.com/positive-intentions/chat
the code related to the video is a faily basic implementation using BabylonJS. it can be found here.
id like to see if i can get handpose-estimation to work well enough to be able to add to the BabylonJS render engine.
im working on something i hope will work like the 8thwall demo here. i couldnt find an open-source alternative to this so i thought id have a crack at it myself. my progress so far is as described here. i dont have much experience in creating games or graphics, so any guidance/help/advice is appriciated.
FAQ:
- why should i use it? - its a proof-of-concept app. for testing and demo purposes only.
- why create it? - it is a hobby project and i can be creative with the approach. its fun to work on.
- what is it? - maybe this article helps.
cross-posted from: https://slrpnk.net/post/11983122
I just found about the rather experimental chaarts. It enhances the standard html and turns it into different charts. Complete with hover text and animations.
It seems to be pretty accessible. And if the user agent doesn't support the fancy css it degrades gracefully to the original
I wrote a post detailing why I use meaning as the criterion for selecting my next web development project.
cross-posted from: https://programming.dev/post/13268260
Hi,
I discovered this webpage
https://developer.mozilla.org/en-US/docs/Glossary/XMLHttpRequestWhere it say
The Fetch API is the modern replacement for XMLHttpRequest.
Without further explain on why so...
Did you (yourself) migrated from XHR to The Fetch API ? and is it better ? or do you know any (not bias) article about it ?
What about performances etc..
Thanks
When using dependencies such as NPM packages, Composer packages. Weather you use a CDN or host the packages on the web server, don't many packages out there require you to display the licenses of the package being used and show attributions?
How would one place this on their website? I even went to several websites to see how they do this and could not find a section and I am sure these website use packages that require the license to be listed and list the attributions.
I can find the licenses and attributions of packages used in many applications on desktop and mobile, usually in the apps "about" page.
cross-posted from: https://programming.dev/post/11085588
We just tagged the first public v4.0.0-alpha so you can start experimenting with it and help us get to a stable release later this year.
I've built a toy ActivityPub server. A single file of about 50KB.
cross-posted from: https://lemmy.ml/post/12252980
Magento, a company based in Berlin offering hosting and e-commerce platform, posted a video illustrating to their EU customers the significant impact of removing PWA support in iOS 17.4 on their services.
Source: https://twitter.com/mysk_co/status/1760585742655308077
cross-posted from: https://programming.dev/post/10271471
It weighs only 181 bytes. Nice.
WebDev
Community for all things Web Development related.