Web Development
- Best Framework for Web Development in 2025
The world of web development is always changing, and keeping up with the latest frameworks is essential for developers who want to create modern, scalable, and user-friendly web applications. As we approach 2025, choosing the best framework for web development 2025 is important for developers and businesses aiming to stay competitive. This blog will discuss the most promising frameworks for web development that should be on your radar for the coming year.
1. React.js
React.js continues to be one of the most popular frameworks for web development. Created by Facebook, React allows developers to build interactive user interfaces with ease. Its component-based architecture makes it reusable and highly efficient for building large-scale applications. In 2025, React remains a top choice for developers looking to create fast and responsive web applications.
2. Vue.js
Vue.js is a lightweight and easy-to-learn framework for web development that has gained popularity due to its simplicity and flexibility. It is perfect for both small-scale projects and larger applications. The framework's ease of integration with existing projects and its clear documentation make it a great tool for developers looking for an alternative to more complex frameworks. In 2025, Vue.js is expected to continue being a preferred choice for developers seeking simplicity without sacrificing functionality.
3. Angular
Angular is a full-fledged framework for web development maintained by Google. Known for its strong features and robust architecture, Angular is ideal for creating dynamic, enterprise-scale web applications. While it has a steeper learning curve compared to React or Vue, it offers powerful tools for data binding, dependency injection, and routing. In 2025, Angular will remain crucial for developers who need a complete framework to handle complex projects efficiently.
4. Next.js
Next.js has risen as a preferred framework for web development for building server-rendered React applications and static websites. It offers great features like automatic static optimization, server-side rendering, and image optimization. These features make Next.js perfect for creating fast and SEO-friendly web applications. For businesses that provide web development services India, adopting Next.js can offer a competitive edge by delivering highly performant websites.
5. Svelte
Svelte has gained attention for its innovative approach to web development. Unlike traditional frameworks, Svelte compiles code at build time, resulting in minimal runtime overhead. This means faster applications with simpler code. For developers who want to move beyond conventional frameworks for web development, Svelte is a must-learn in 2025 due to its performance benefits and straightforward syntax.
6. Django
For those interested in server-side frameworks for web development, Django stands out as one of the best options for building powerful, secure web applications with Python. Django comes with built-in tools for user authentication, database management, and security, making it an all-in-one solution. Its emphasis on best practices helps developers create scalable and maintainable projects. As the use of Python grows, Django will continue to be a significant framework for web development in 2025.
7. Ruby on Rails
Ruby on Rails, or Rails, has been a reliable framework for web development for years, known for its simplicity and speed of development. It follows a convention-over-configuration approach, which means that developers can get projects off the ground quickly with less boilerplate code. For startups and small businesses looking to deploy applications rapidly, Ruby on Rails will remain a valuable tool in 2025.
8. ASP.NET Core
For those who prefer using Microsoft technologies, ASP.NET Core is an excellent framework for web development. It is cross-platform, open-source, and well-suited for creating high-performance web applications. With support for various programming languages, ASP.NET Core offers flexibility and scalability, making it a strong contender in 2025, especially for enterprise-level solutions.
9. Laravel
Laravel is a popular framework for web development using PHP, loved for its elegant syntax and comprehensive tools. It simplifies common tasks such as routing, authentication, and caching. Laravel is a great choice for developers who want to build robust, scalable web applications without a steep learning curve. In 2025, Laravel will continue to be a powerful tool for PHP developers and agencies providing web development services India.
10. FastAPI
For developers looking to create APIs with Python, FastAPI has become the go-to framework for web development. It is known for its speed, ease of use, and automatic documentation generation. FastAPI makes it easy to build high-performance, modern web APIs, and its use is expected to grow as more developers appreciate its efficiency in 2025.
Conclusion
Choosing the right framework for web development services India can make a big difference in creating fast, reliable, and easy-to-maintain web applications. As we approach 2025, the best framework depends on your project needs and your team's expertise. Key frameworks include:
React.js – Flexible Vue.js – Simple Django – Powerful ASP.NET Core – Robust
These frameworks can help developers and companies in India speed up their development process and create top-quality web applications. Learning these tools will help you stay competitive and build cutting-edge projects.
- Why is my 3d pointer not being displayed in my webapp?
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); ```
- Async Javascript State Managementpositive-intentions.com Dim: Async State Management | positive-intentions
I'm working on creating something I can call "functional web components".
- React-Like Functional Web Componentspositive-intentions.com Todo list With Functional Web Components | Welcome to positive-intentions
I'm working on creating something I can call "functional web components".
Functional Web Components
https://positive-intentions.com/blog/dim-todo-list
Github: https://github.com/positive-intentions/dim
Demo: https://dim.positive-intentions.com
- An Abridged History of Safari Showstoppers - Webventureswebventures.rejh.nl An Abridged History of Safari Showstoppers - Webventures
TL;DR: iOS Safari is more than an inconvenience for developers, it's the fundamental reason interoperability has been stymied in...
TL;DR: iOS Safari is more than an inconvenience for developers, it's the fundamental reason interoperability has been stymied in...
- [Solved] Having trouble with Jekyll on a new laptop: Help a casual web dev dum-dum out!
Since I moved to a new laptop, my Jekyll setup seems to have become unusable. It appears the gems required by my site aren't found, or properly configured, even after a
bundle install
command that updated a bunch of them.Error messages on bundle exec jekyll serve: https://pastebin.com/gyg8YpMxResult of
bundle install
: https://pastebin.com/LKSstmJtI'm by no means a Jekyll or Ruby expert (barely a user), but I used to have a tolerably functional environment to update my site. Any help on getting that up and running again is much appreciated!
Update 1:
I managed to solve the SASS issue that @Kissaki@programming.dev pointed out. Now the bundler asks about a possible typo in a gallery plugin 😰
See new error messages on
bundle exec jekyll serve
: https://pastebin.com/kk6HHv7Y I hope not every line in there is an error I have to fix...Update 2 (solved)
Edited the RB plugin file according to the error message, and ...that was all? The site generates as in the olden days.
Thank you all who chipped in with advice!
- [SOFTWARE REQUEST] Core for new API
I am currently working on a fairly old website service for the company's internal needs. The stack is quite old - PHP 5.3. It so happened that company can't abandon it right now.
... In short, I received a task to develop a REST API for this service. It is clear that I cannot use the current stack. What can I use as a standalone core for the new API? The main thing for me is the speed of development and ease of learning. For example, I would like Bearer authorization / some rights model out of box.
Something like Laravel, but separate instance of it just for the API seems a little overkill for me. What you can advise me? Any boilerplates / software recommendations are welcomed.
PS: My database is MSSQL 2016, so it could be a problem.
- How to create functional webcomponents
https://positive-intentions.com/blog/dim-functional-webcomponents/
im investigating an idea i have about functional webcomponents after some experience with Lit.
Lit is a nice lightweight UI framework, but i didnt like that it was using class-based components.
Vue has a nice approach but i like working with the syntax that React used and i wondered if with webcomponents i could create a functional UI framework that didnt need to be transpiled.
i think the article is already quite long, so i think i will create a separate one as a tutorial for it.
note: im not trying to push "yet another ui framework", this is an investigation to see what is possible. this article is intended as educational.
- Always support compressed response in an API serviceashishb.net Always support compressed response in an API service
If you run any web service always enable support for serving compressed responses. It will save egress bandwidth costs for you. And, more importantly, for your users. Over time, the servers as well as client devices have become more powerful, so, compressing/decompressing data on the fly is cheap.
- The HTTP QUERY Methodwww.ietf.org The HTTP QUERY Method
This specification defines a new HTTP method, QUERY, as a safe, idempotent request method that can carry request content.
- Best way to add a blog to an existing, static website?
I exported a Wordpress site as a static site and have been hosting that on Gitlab. I'd like to start updating the blog again and I'm wondering how to go about it.
For the blog, I've been adding/coding the entries manually, which I still prefer to using Wordpress. Now I have someone who needs to take over the blog and I need something more simple for them.
I've looked into DropInBlog ( https://dropinblog.com ) but it's way beyond our budget, so I've been thinking to either:
-
Give them git access and let them add a text file and image to a special directory when they want to post. Then I can have a script run a few times per hour which converts that into a blog post. I'd also need to update the blog index with my own code.
-
Let them use something RSS based with a nice interface and scrape that to generate the blog. Mastodon is one option, as is Wordpress. Ideally the blog they maintain would not be accessible to others on the web though. I don't want to split our SEO presence.
Does anyone have a better suggestion? The website doesn't use a framework like Jekyll or any of those. It's just HTML, CSS and JS.
-
- Need to know about npm
I'm following the odin project to learn web development. I had read about malicious packages in npm multiple times, so I avoided it until now. I'm on the webpack lesson now, and to use webpack, I need to install it using npm. I also see that it has many dependencies, and those dependencies will have other depenedencies and so on.
Why is it like this? Is there any other tool like webpack that doesn't require npm? Or rather, can someone clarify how to properly use npm or link a guide that explains it? I have this kind of fear and reluctance about using npm after all the things I read.
- Building a browser using Servo as a web engine! - Servo, the embeddable, independent, memory-safe, modular, parallel web rendering engineservo.org Building a browser using Servo as a web engine! - Servo, the embeddable, independent, memory-safe, modular, parallel web rendering engine
Let's build another web browser based on Servo!
Let's build another web browser based on Servo!
- Reactivity and Reactive Programming [Blog Post]cosmicbyt.es Reactivity and Reactive Programming
Nearly all modern browser UI frameworks boast Reactivity as a core feature. What is Reactivity all about? Is it useful or applicable outside of frontend development? what is the hype all about anyways?
Most modern JavaScript UI frameworks boast Reactivity, but have you ever wondered what that means exactly?
In my opinion, Reactivity is largely responsible for making modern frontend development unintuitive to outsiders.
This blog post explains what Reactivity is, and how it manifested in the frontend development world today.
You might find this interesting if you're: a frontend dev unfamiliar with the concept, a non-frontend dev interested in frontend, or just curious what Reactivity is!
- Client-side JavaScript and React criticism: What comes next?molily.de Client-side JavaScript and React criticism: What comes next? · molily
How do we improve JavaScript usage, teach progressive enhancement and reconcile the community?
> How do we improve JavaScript usage, teach progressive enhancement and reconcile the community?
- Where to start with a forum or community site and what should I expect it to cost?
I would like to create a site that that allows people to select a category and/or a sub-category and invite people to join and partake in something for a limited time period determined by the OP, but also allowing other users to suggest alternative options as a votable option.
I have no idea where to start with any of this.
Is it just forum software that I should be looking at, and could anyone recommend one if it is. Also how much should I be looking at to begin with?
EDIT - Thanks everyone, all good options to look at. I am going to try a Lemmy Sub, as that seems to be the most favoured answer by users. Hopefully I will get to grips with it. 🙂
- Look Ma, No CDN!jade.ellis.link Look Ma, No CDN!
CDNs are common - but are they really necessary? Is a single origin the performance pitfall many think it is?
- Developers Rail Against JavaScript ‘Merchants of Complexity’thenewstack.io Developers Rail Against JavaScript ‘Merchants of Complexity’
When both Pieter Levels and Alex Russell convincingly argue against using complex JavaScript frameworks, maybe frontend devs should listen.
The rebelling against JavaScript frameworks continues. In the latest Lex Fridman interview, AI app developer Pieter Levels explained that he builds all his apps with vanilla HTML, PHP, a bit of JavaScript via jQuery, and SQLite. No fancy JavaScript frameworks, no modern programming languages, no Wasm.
“I’m seeing a revival now,” said Levels, regarding PHP. “People are getting sick of frameworks. All the JavaScript frameworks are so… what do you call it, like [un]wieldy. It takes so much work to just maintain this code, and then it updates to a new version, you need to change everything. PHP just stays the same and works.”
- CSS Only 3D Robot
Hello everyone! This is something I made back in university to test my CSS skills. I haven't practiced any HTML/CSS since then, but I thought I'd finally share this project with the community. Hope you like it!
- In a leaked recording, Amazon cloud chief tells employees that most developers could stop coding soon as AI takes overwww.businessinsider.com In a leaked recording, Amazon cloud chief tells employees that most developers could stop coding soon as AI takes over
Matt Garman sees a shift in software development as AI automates coding, telling staff to enhance product-management skills to stay competitive.
> Matt Garman sees a shift in software development as AI automates coding, telling staff to enhance product-management skills to stay competitive.
- Create a `clip-path` animated ?
Hi,
I would like to use a rectangle that move (left to right) to reveal an
element
/image
like this
The white box shall be the image to display
But I'm already block at my svg animation
svg <svg viewBox="0 0 265.135 68.642" xmlns="http://www.w3.org/2000/svg"> <g x="-55.790085" y="0.79151762"> <rect style="fill:#ffcc00;stroke-width:2.46513;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke fill markers;stop-color:#000000" width="55.465603" height="151.60599" transform="rotate(45)" /> <animate attributeName="x" values="-55.790085;265" dur="5s" repeatCount="indefinite" /> </g> </svg>
Because the rectangle is not moving :'(
Any ideas ?
Thanks.
- I built an AI-powered quiz application with Next.js and OpenAIdev.to Building an AI-powered quiz application with Next.js and OpenAI
In this tutorial, you'll learn how to build an AI-powered quiz application that enables users to...
- Nginx how enable CORS for multi origins ?
Hi everyone,
I would like to enable Cross-Origin Resource Sharing on my Nginx server. for few origins (cors requestor)/domains.
I've found this article https://www.juannicolas.eu/how-to-set-up-nginx-cors-multiple-origins that is nice, but not complete and on my browser seem really hard to read due to the layout 🤮
So I've opened a CodeBerg git repository for the good soul that want to perfect this piece of code the allow the most of use to use CORS with Nginx.
https://codeberg.org/R1ckSanchez_C137/BestOfxxx/src/branch/main/Nginx/CORS_MultiDomains.py \ and \ https://codeberg.org/R1ckSanchez_C137/BestOfxxx/issues \
If you don't want to create an account on codeberg feel free to post your code here !
```nginx server { # Server
map "$http_origin" $cors { # map in Nginx is somewhat like a switch case in a programming language. default ''; #Seem to set $cors to '' empty string if none of the follwing rexeg match ? "~^https:\/\/([\w-\.]+\.)?example.com$" "$http_origin"; #regex domain match # ~ mean I suppose the string is RegEx ? # Need to come with a RegEx expression that match https://anything.example.com[optional ports and Query string ?X=Y] "~^https:\/\/([\w-\.]+\.)?example2.com$" "$http_origin"; #regex domain match }
location /static {
# if preflight request, we will cache it if ($request_method = 'OPTIONS') { add_header 'Access-Control-Max-Age' 1728000; #20 days add_header 'Content-Type' 'text/plain charset=UTF-8'; add_header 'Content-Length' 0; return 204; #https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204 }
if ($cors != "") { add_header 'Access-Control-Allow-Origin' "$cors" always; # <-- Variable $cors add_header 'Access-Control-Allow-Credentials' 'true' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Accept, Authorization, Cache-Control, Content-Type, DNT, If-Modified-Since, Keep-Alive, Origin, User-Agent, X-Requested-With' always;}
# configuration lines...
} }
} ```
- Deno's Standard Library for JavaScript Finally Stabilized at v1 | 3min 5sec Video | Aug 8, 2024
YouTube Video
Click to view this content.
Video Description
> Many programming languages have standard libraries. What about JavaScript? 🤔️ > > Deno's goal is to simplify programming, and part of that is to provide the JavaScript community with a carefully audited standard library (that works in Deno and Node) that offers utility functions for data manipulation, web-related logic, and more. We created the Deno Standard Library in 2021, and four years, 151 releases, and over 4k commits later, we're thrilled to finally announce that it's 30 modules are finally stabilized at v1. > > Learn more about the Deno Standard Library > > Read about our stabilization process for the library
- CSS finally adds vertical centering in 2024build-your-own.org CSS finally adds vertical centering in 2024 | Blog | build-your-own.org
CSS finally adds vertical centering in 2024
cross-posted from: https://lemmy.ca/post/27261082
- I wrote an article: What Are UI and UX? And What’s The Difference?medium.com What Are UI and UX? And What’s The Difference?
Understanding the difference, as clear as possible.
- I just fixed a bug that was over 10 years old.
I have a dust covered personal project that I created in ACTIONSCRIPT that I started porting to JS recently. I had an audio bug because the synth I created was too simple, so every time a note stopped playing it made an annoying click sound.
Just fixed it by using attack/decay parameters in a gain node.
It feels good. next steps feel a lot easier, and I can think about doing some more fun stuff.
- I need some clarification on ul li vs divs
Hello,
I'm a Sr Dev who mostly has done back-end work but I'm "dangerous enough" in front end frameworks to get things done in my job.
I have another Sr Dev on my team who is ADAMANT on using ul/ol's everywhere. And I mean EVERYWHERE.
Navigation menu items will get done as a list.
Say I have a list of key value pairs or tags describing an item on a page, that's a list. If there are two sections on a page that's also a list. Even forms are built as lists of inputs and buttons. To the point where I'm positive if I told them to recreate the google front page I'm 100% they'd make a ul and a li for the image, another for the box and a separate li for the buttons.
My frustration is that every piece of documentation regarding ordered lists and unordered lists are for literally listings out items as numbered or bulleted lists, not logically grouping things on a page. Also our code is littered with extra css to strip out the bullet points and numbers on a basic li item.
I've worked on several projects and this is the first time I've ever seen lists so overused. Is this normal on some projects? It feels wrong but I don't know the exact terminology to use to explain why, given my inexperience in front end development.
- Shared VR space over P2P
YouTube Video
Click to view this content.
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.
- I won! Creating a top-notch game with Phaser in under 2 weeksreitgames.com I won! Creating a top-notch game with Phaser in under 2 weeks
Ever wondered what it takes to transform a simple idea into an award-winning game in just two weeks? Come along as I share my challenging and exciting experience in this year's Gamedev.js game jam.
I hope this is okay. As a web dev who loves phaser, I love this stuff.
If it's not, I apologize profusely.
- Has anyone else had issues with domain registries randomly suspending a domain?
Apologies if this is the wrong community. I spent some time searching for a good one, and this seemed to be fairly applicable.
I've owned several domains over the years, but recently I purchased another one (
goat.rest
) to house a little side project I was working on. For about two weeks, everything was running fine, and then out of the blue the site disappeared. After some investigation, I figured out that the domain had been suspended by the registry, with seemingly no reason or course of action to get it back. I triple-checked, and although the TLD for the domain is intended for restaurants, it should be open for other uses too. The site wasn't spammy, explicit, or in any way content that would be cause for removal. I sent an email to the company that owns the TLD, and three days later the block was removed, and hours later I got an incredibly vague and short email stating as such.While the site was down, I did a little research and found a post where someone had a similar issue, but I haven't been able to find much else. Do registries just randomly, automatically suspend domains when they want to?
I wrote a blog post going into a little more detail about the whole situation, but mainly I'm just really curious about the question I asked in the title. Am I just super unlucky to have this happen to me, or have other people experienced a similar situation?
- Do you need an email account with a web host if you use Gmail
A friends business email goes through to his gmail account, but he also pays for an email account with his web host. Is it necessary to keep paying for this email account, does he need it if the email goes through to gmail?
EDIT: What I know is, they both receive and send emails from @theirdomain.com via their Gmail. They have their domain registered with a seperate company than the web host and have access to their DNS records there. With the hosting company they pay for email in addition to their hosting plan.
My friend wants to avoid the extra cost of the email account if possible, and I thought it wasn't required to have an email with your your webhost if setting up the DNS records properly, but not 100% sure. We wanted to get independent advice before proceeding, since the host has an incentive for my friend to stay on the email plan.
- Hosting wordpress in the UK
Hi, I am looking for a WordPress host in the UK (or europe) and I have been researching them extensively, but would appreciate hearing people's experiences.
My research has led me to a Kualo (www.kualo.com), they offer free SSL, unlimited bandwidth, have good reviews on TrustPilot, provide cloudflare CDN, and have a faily decent knowledge base.
Has anyone used them and can offer personal experience? Or any other hosting recommendations? Thanks
- Applying the four principles of accessibilityclearleft.com Applying the four principles of accessibility
[Web Content Accessibility Guidelines](https://www.w3.org/WAI/standards-guidelines/wcag/)—or WCAG—looks very daunting. It’s a lot to take in. It’s kind of overwhelming. It’s hard to know where to start.
- Interactive CSS grid tutorialishadeed.com CSS Grid Areas
A fresh look at the CSS grid template areas and how to take advantage of its full potential today.
> > > CSS Grid support has been widely available since March 2017 in all major browsers. Yet, here we are in 2024, and I still see few people using the grid template areas feature. > >
> > > It’s no surprise that many avoid template areas as making sense of the grid is challenging enough. In this interactive article, I aim to shed light on this feature and, hopefully, convince you to use it more often. Once you see the simplicity and power of template areas, you may reach for them much more frequently. > >
- CSS Selectorscss-tricks.com CSS Selectors | CSS-Tricks
A complete guide covering all of the various methods we have to select elements in CSS and how to use them for applying styles.