ObjetoCanvas y ObjetoLogo

Size
7,884 Kb
Views
28,336

How do I make an objetocanvas y objetologo?

-ObjetoCanvas : Object for canvas2d or Three.js to make thinks easyer -ObjetoLogo : Put a link to my wep page in the bottom right corner. What is a objetocanvas y objetologo? How do you make a objetocanvas y objetologo? This script and codes were developed by Josep Antoni Bover Comas on 27 August 2022, Saturday.

ObjetoCanvas y ObjetoLogo Previews

ObjetoCanvas y ObjetoLogo - Script Codes HTML Codes

<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>ObjetoCanvas y ObjetoLogo</title> <link rel="stylesheet" href="css/style.css">
</head>
<body> <script src="js/index.js"></script>
</body>
</html>

ObjetoCanvas y ObjetoLogo - Script Codes CSS Codes

/*
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
*/
/* Created on : 05-ago-2016, 23:38:27 Author : devildrey33
*/
/* Fuente del logo */
@import url('http://fonts.googleapis.com/css?family=Architects+Daughter|Orbitron');
body { margin:0px; padding:0px; }
/* Estilos para los marcos informativos */
#Cabecera { margin:0px; height:100%; border-top:none; color:#FFFFFF; background:rgba(49,46,53, 1); z-index:10; width:100%; overflow:hidden; position:fixed; top:0px; bottom:0px;
}
#Cabecera > #Cabecera_Canvas { width:100%; height:100%;
}
#Cabecera > #Cabecera_Cargando,
#Cabecera > #Cabecera_PausaAni,
#Cabecera > #Cabecera_Stats { transition:0.3s cubic-bezier(.33,.05,.69,1.59); z-index:13; padding:10px; margin:5px; background-color: rgba(37,35,40, 0.6); color:#FFF; text-shadow:1px 1px 1px #000; position:absolute; border:1px solid #353338;
}
#Cabecera > #Cabecera_Cargando { top:0px; left:50%; transform:perspective(600px) rotateX(-90deg) translateX(-50%);
}
#Cabecera > #Cabecera_Stats { transform-origin: top center; transform:perspective(600px) rotateX(-90deg); right:0px;
}
#Cabecera > #Cabecera_PausaAni { transform-origin: top center; transform:perspective(600px) rotateX(-90deg); top:0px; right:0px;
}
/* Solo se muestra la información de la animación si la animación está activa (puede estar visible pero inactiva si la web no tiene el foco) */
#Cabecera[animar=true]:hover > #Cabecera_Stats { transform:perspective(600px) rotateX(0deg);
}
/* Solo se muestra la información de la animación si la animación está activa (puede estar visible pero inactiva si la web no tiene el foco) */
#Cabecera[animar=false] > #Cabecera_PausaAni { transform:perspective(600px) rotateX(0deg);
}
/* Solo se muestra el texto cargando mientras el atributo cargando sea true (necesario para advertir de la carga de texturas) */
#Cabecera[cargando=true] > #Cabecera_Cargando { transform:perspective(600px) rotateX(0deg) translateX(-50%);
}
/* Fuente del logo */
#Logo_devildrey33 { position:fixed; right:10px; bottom:10px; width:40px; height:40px; border-radius:4px; border:2px solid #000; background-image:radial-gradient(rgba(35, 35, 35, 0.5), rgba(0, 0, 0, 0.95)); cursor:pointer; transition:0.4s cubic-bezier(.33,.05,.69,1.59); overflow:hidden; padding:10px; font-family: 'Orbitron',sans-serif; font-size:26px; text-shadow:1px 1px 1px #000; z-index:1000;
}
#Logo_devildrey33:hover { width:280px; border:2px solid rgb(234, 80, 78); /* border-radius:10px;*/
}
#Logo_devildrey33 > img { position:absolute; right:6px; width:48px; height:48px; top:6px;
}
#Logo_devildrey33 > div { bottom:0px; margin-top:3px; transition:0.4s; width:4800px; /* 12 caracters * 400px */
}
#Logo_devildrey33:hover > div { bottom:inherit;
}
#Logo_devildrey33:hover > div > span { position:relative; opacity:1; left:400px; animation: AnimacionLogo 0.5s 1 cubic-bezier(.17,-0.42,0,1.15); animation-fill-mode:forwards;
}
#Logo_devildrey33 > div > span { transition:0.5s cubic-bezier(.17,-0.42,0,1.15); opacity:0; position: relative; display: inline-block; color:#FFF;
}
/* Color rojo del 33 */
#Logo_devildrey33 > div > span:nth-child(11), #Logo_devildrey33 > div > span:nth-child(12) { color: rgb(234, 80, 78);
}
#Logo_devildrey33:hover > div > span:nth-child(1) { animation-delay: 0.55s; }
#Logo_devildrey33:hover > div > span:nth-child(2) { animation-delay: 0.50s; }
#Logo_devildrey33:hover > div > span:nth-child(3) { animation-delay: 0.45s; }
#Logo_devildrey33:hover > div > span:nth-child(4) { animation-delay: 0.40s; }
#Logo_devildrey33:hover > div > span:nth-child(5) { animation-delay: 0.35s; }
#Logo_devildrey33:hover > div > span:nth-child(6) { animation-delay: 0.30s; }
#Logo_devildrey33:hover > div > span:nth-child(7) { animation-delay: 0.25s; }
#Logo_devildrey33:hover > div > span:nth-child(8) { animation-delay: 0.20s; }
#Logo_devildrey33:hover > div > span:nth-child(9) { animation-delay: 0.15s; }
#Logo_devildrey33:hover > div > span:nth-child(10) { animation-delay: 0.10s; }
#Logo_devildrey33:hover > div > span:nth-child(11) { animation-delay: 0.05s; }
#Logo_devildrey33:hover > div > span:nth-child(12) { animation-delay: 0.0s; }
@keyframes AnimacionLogo { 0% { left:500px; } 100% { left:5px; }
}
#Logo_devildrey33 > img { transition:0.4s;
}
#Logo_devildrey33:hover > img { transform: scale(1.5, 1.5);
}

ObjetoCanvas y ObjetoLogo - Script Codes JS Codes

/* Fusión del ObjetoCanvas (originalmente destinado a tests de banners) con el ObjetoBanner Creado el 14/10/2016 por Josep Antoni Bover Comas para devildrey33.es Ultima modificación : 28/10/2016 */
/* Opciones['Tipo'] puede ser : - 2d , Canvas con funciones 2D. (POR DEFECTO) - THREE , Canvas utilizando la API del Three.js Opciones['Ancho'] por defecto el ancho se adapta al contenedor, establece un ancho en pixeles para que sea fijo. Opciones['Alto'] por defecto la altura se adapta al contenedor, establece una altura en pixeles para que sea fija. Opciones['Entorno'] puede ser : - Normal , Canvas para crear tests rapidos. (POR DEFECTO) - Banner , Canvas diseñado para el Banner de devildrey33. Opciones['MostrarFPS'] puede ser : true o false. (TRUE POR DEFECTO) Opciones['ElementoRaiz'] elemento del HTML donde se creará el canvas (POR DEFECTO es 'document.body') Opciones['ColorFondo'] color del fondo en HEX (SOLO para THREE.js) (POR DEFECTO es '0x312E35' gris oscuro) */
ObjetoCanvas = function(Opciones) { // Opciones por defecto this.OpcionesCanvas = { 'Tipo' : '2d', 'Ancho' : 'Auto', 'Alto' : 'Auto', 'Entorno' : 'Normal', 'MostrarFPS' : true, 'ElementoRaiz' : document.body, 'Pausar' : true, // Pausar si el canvas está en segundo plano 'ColorFondo' : 0x312E35 // Color del fondo por defecto (solo si usas THREE.js) }; // Copio las nuevas opciones encima de las opciones por defecto if (typeof Opciones === 'object') { for (var Indice in Opciones) { this.OpcionesCanvas[Indice] = Opciones[Indice]; }
/* Opciones.forEach(function(Elemento, Indice, Array) { this.Opciones[Indice] = Elemento; }.bind(this));*/ } // En el entorno Normal hay que crear todas las etiquetas if (this.OpcionesCanvas['Entorno'] === 'Normal') { // Creo la cabecera vacia var PreCabecera = document.createElement('header'); PreCabecera.id = "Cabecera"; this.OpcionesCanvas['ElementoRaiz'].appendChild(PreCabecera); // Creo las etiquetas que contienen información adicional sobre la animación this.Cabecera = document.getElementById("Cabecera"); this.Cabecera.innerHTML = '<div id="Cabecera_Cargando">Cargando animación...</div>' + "<div id='Cabecera_Stats'>0 FPS</div>" + "<canvas id='Cabecera_Canvas'></canvas>" + '<div id="Cabecera_PausaAni">El canvas está en segundo plano, animación en pausa.</div>'; } // En el entorno Banner las etiquetas ya estan creadas, pero hay que eliminar y volver a crear el canvas if (this.OpcionesCanvas['Entorno'] === 'Banner') { this.Cabecera = document.getElementById("Cabecera"); // Hay que eliminar la etiqueta canvas por que al crear un 2d context encima de un webgl context y viceversa produce error. if (document.getElementById('Cabecera_Canvas')) { this.Cabecera.removeChild(document.getElementById('Cabecera_Canvas')); } this.Cabecera.innerHTML = this.Cabecera.innerHTML + "<canvas id='Cabecera_Canvas'></canvas>"; // Marco que contiene la información de la animación del banner document.getElementById("CabeceraAutorAni_HTML").innerHTML = "<div>"+ this.Nombre +"</div>" + "<div><span style='color:#AAA;'>Concepto original : </span><b>" + this.IdeaOriginal + "</b></div>" + "<a href='" + this.URL + "' target='_blank'>" + this.NombreURL + "</a>"; } // Asigno el estado cargando, que muestra una ventana que avisa al usuario. this.Cabecera.setAttribute("cargando", true); this.Cabecera.setAttribute("animar", true); // Obtengo la etiqueta canvas this.Canvas = document.getElementById("Cabecera_Canvas"); // Tamaño del canvas this.Ancho = 0; // Ancho del canvas this.Alto = 0; // Altura del canvas // Determino el ancho y altura del canvas (fijo o variable) if (this.OpcionesCanvas.Ancho !== "Auto") { this.Ancho = this.OpcionesCanvas.Ancho; } if (this.OpcionesCanvas.Alto !== "Auto") { this.Alto = this.OpcionesCanvas.Alto; } // Si el canvas es de ancho fijo, añado el css para centrar-lo if (this.OpcionesCanvas.Ancho !== "Auto") { this.Canvas.style.width = this.Ancho + "px"; this.Canvas.style.left = "calc(50% - (" + this.Ancho + "px / 2))"; } if (this.OpcionesCanvas.Alto !== "Auto") { this.Canvas.style.height = this.Alto + "px"; this.Canvas.style.top = "calc(50% - (" + this.Ancho + "px / 2))"; } // Creación del contexto try { if (this.OpcionesCanvas.Tipo.toLowerCase() === '2d') { this.Context = this.Canvas.getContext("2d"); // Contexto 2D console.log("ObjetoCanvas iniciado en modo 2d"); } else if (this.OpcionesCanvas.Tipo.toLowerCase() === 'three') { if (this.PixelRatio() > 1) { // El antialias no va con el samsung galaxy alpha... this.Context = new THREE.WebGLRenderer({ canvas : this.Canvas }); // Contexto THREE.JS console.log("ObjetoCanvas iniciado en modo THREE sin antialias"); } else { this.Context = new THREE.WebGLRenderer({ canvas : this.Canvas, antialias : true }); // Contexto THREE.JS console.log("ObjetoCanvas iniciado en modo THREE con antialias"); } this.Context.setClearColor(this.OpcionesCanvas.ColorFondo, 1); // Color del fondo } } catch ( error ) { document.getElementById("Cabecera_Cargando").innerHTML = "Error iniciando WebGL : " + error; return false; } this.RAFID = 0; // Request Animation Frame ID this.FPS_UltimoTick = Date.now() + 1000; // Ultimo Tick del sistema + 1000ms this.FPS_Contador = 0; // Contador de frames por segundo this.FocoWeb = true; // Foco de la ventana de la web this.Tick = 0; // Date.now actualizado en cada frame // Calculo el tamaño del canvas this.EventoRedimensionar(); // Temporizador para la animación this.RAFID = window.requestAnimationFrame(this.Actualizar.bind(this)); // Evento mouse movimiento this.EnlazarEventos(); // Estado cargando this.Cargando(true); if (this.OpcionesCanvas.MostrarFPS === false) { // Escondo el marco de los FPS document.getElementById("Cabecera_Stats").style.display = "none"; } return true;
};
ObjetoCanvas.prototype.Terminar = function() { if (this.RAFID !== 0) { window.cancelAnimationFrame(this.RAFID); } if (this.OpcionesCanvas.Entorno === "Normal") { this.Cabecera.removeEventListener('mousedown', this.hEventoMousePresionado); this.Cabecera.removeEventListener('mouseup', this.hEventoMouseSoltado); window.removeEventListener('keydown', this.hEventoTeclaPresionada); window.removeEventListener('keyup', this.hEventoTeclaSoltada); } this.Cabecera.removeEventListener('mousemove', this.hEventoMouseMove); this.Cabecera.removeEventListener('mouseenter', this.hEventoMouseEnter); this.Cabecera.removeEventListener('mouseleave', this.hEventoMouseLeave); window.removeEventListener('resize', this.hEventoRedimensionar); window.removeEventListener('scroll', this.hEventoScroll); window.removeEventListener('blur', this.hEventoFocoPerdido); window.removeEventListener('focus', this.hEventoFocoRecibido); console.log("ObjetoCanvas.Terminar");
};
ObjetoCanvas.prototype.EnlazarEventos = function() { // Necesito guardar una variable con cada evento reconvertido con bind, para poder hacer mas tarde el removeEventListener if (this.OpcionesCanvas.Entorno === "Normal") { this.hEventoMousePresionado = this.EventoMousePresionado.bind(this); this.hEventoMouseSoltado = this.EventoMouseSoltado.bind(this); this.hEventoTeclaPresionada = this.EventoTeclaPresionada.bind(this); this.hEventoTeclaSoltada = this.EventoTeclaSoltada.bind(this); this.Cabecera.addEventListener('mousedown', this.hEventoMousePresionado); this.Cabecera.addEventListener('mouseup', this.hEventoMouseSoltado); window.addEventListener('keydown', this.hEventoTeclaPresionada); window.addEventListener('keyup', this.hEventoTeclaSoltada); } this.hEventoMouseMove = this.EventoMouseMove.bind(this); this.hEventoMouseEnter = this.EventoMouseEnter.bind(this); this.hEventoMouseLeave = this.EventoMouseLeave.bind(this); this.hEventoRedimensionar = this.EventoRedimensionar.bind(this); this.hEventoScroll = this.EventoScroll.bind(this); this.hEventoFocoPerdido = this.EventoFocoPerdido.bind(this); this.hEventoFocoRecibido = this.EventoFocoRecibido.bind(this); this.Cabecera.addEventListener('mousemove', this.hEventoMouseMove); this.Cabecera.addEventListener('mouseenter', this.hEventoMouseEnter); this.Cabecera.addEventListener('mouseleave', this.hEventoMouseLeave); window.addEventListener('resize', this.hEventoRedimensionar); window.addEventListener('scroll', this.hEventoScroll); window.addEventListener('blur', this.hEventoFocoPerdido); window.addEventListener('focus', this.hEventoFocoRecibido);
};
// Evento que salta cuando se obtiene el foco de la ventana
ObjetoCanvas.prototype.EventoFocoRecibido = function() { console.log("Foco de la ventana recibido"); this.FocoWeb = true; if (this.OpcionesCanvas.Entorno === "Normal") { this.EventoReanudar(); } // En el entorno banner, solo se reanuda si el banner es visible en la ventana else if (this.OpcionesCanvas.Entorno === "Banner" && window.scrollX < 190) { this.EventoReanudar(); }
};
// Evento que salta cuando se pierde el foco de la ventana
ObjetoCanvas.prototype.EventoFocoPerdido = function() { console.log("Foco de la ventana perdido"); this.FocoWeb = false; this.EventoPausa();
};
// Función que devuelve el pixel ratio del dispositivo actual
ObjetoCanvas.prototype.PixelRatio = function() { var ratio = 1; // To account for zoom, change to use deviceXDPI instead of systemXDPI if (window.screen.systemXDPI !== undefined && window.screen.logicalXDPI !== undefined && window.screen.systemXDPI > window.screen.logicalXDPI) { // Only allow for values > 1 ratio = window.screen.systemXDPI / window.screen.logicalXDPI; } else if (window.devicePixelRatio !== undefined) { ratio = window.devicePixelRatio; } return ratio;
};
// Función que determina el estado de carga (cargando/completo) true/false
ObjetoCanvas.prototype.Cargando = function(carga) { document.getElementById("Cabecera").setAttribute("cargando", carga);
};
// Función interna utilizada por requestAnimationFrame para actualizar y pintar la animación
ObjetoCanvas.prototype.Actualizar = function() { this.Tick = Date.now(); this.FPS(); this.RAFID = window.requestAnimationFrame(this.Actualizar.bind(this)); this.Pintar.apply(this);
};
// Función que procesa el evento keydown
ObjetoCanvas.prototype.EventoTeclaPresionada = function(event) { if (typeof(this.TeclaPresionada) !== "undefined") { this.TeclaPresionada.apply(this, [ event ]); }
};
// Función que procesa el evento keyup
ObjetoCanvas.prototype.EventoTeclaSoltada = function(event) { if (typeof(this.TeclaSoltada) !== "undefined") { this.TeclaSoltada.apply(this, [ event ]); }
};
// Función que procesa el evento mousemove
ObjetoCanvas.prototype.EventoMouseMove = function(event) { if (typeof(this.MouseMove) !== "undefined") { this.MouseMove.apply(this, [ event ] ); }
};
// Función que procesa el evento mousedown
ObjetoCanvas.prototype.EventoMousePresionado = function(event) { if (typeof(this.MousePresionado) !== "undefined") { this.MousePresionado.apply(this, [ event ]); }
};
// Función que procesa el evento mouseup
ObjetoCanvas.prototype.EventoMouseSoltado = function(event) { if (typeof(this.MouseSoltado) !== "undefined") { this.MouseSoltado.apply(this, [ event ]); }
};
// Función que procesa el evento mousemove
ObjetoCanvas.prototype.EventoMouseEnter = function(event) { console.log("ObjetoCanvas.EventoMouseEnter"); if (typeof(this.MouseEnter) !== "undefined") { this.MouseEnter.apply(this, [ event ]); }
};
// Función que procesa el evento mousemove
ObjetoCanvas.prototype.EventoMouseLeave = function(event) { console.log("ObjetoCanvas.EventoMouseLeave"); if (typeof(this.MouseLeave) !== "undefined") { this.MouseLeave.apply(this, [ event ]); }
};
// Función que obtiene el tamaño del canvas una vez redimensionado.
ObjetoCanvas.prototype.EventoRedimensionar = function() { // Calculo el nuevo ancho y la nueva altura (si no son fijas) if (this.OpcionesCanvas.Ancho === "Auto") { this.Ancho = document.getElementById("Cabecera").offsetWidth; } if (this.OpcionesCanvas.Alto === "Auto") { this.Alto = document.getElementById("Cabecera").offsetHeight; } // Asigno el alto y el ancho a los atributos del canvas this.Canvas.setAttribute("width", this.Ancho); this.Canvas.setAttribute("height", this.Alto); if (this.OpcionesCanvas.Tipo.toLowerCase() === "three") { // redimensionar el THREE.JS this.Context.setSize(this.Ancho, this.Alto); if (this.Camara !== null && typeof(this.Camara) !== 'undefined') { // Si hay una camara creada this.Camara.aspect = this.Ancho / this.Alto; this.Camara.updateProjectionMatrix(); } } // if (typeof(this.Redimensionar) !== "undefined") { this.Redimensionar.apply(this); }
};
// Función para pausar la animación
// - Hay que detectar cuando la animación no es visible y cuando la ventana no tiene el foco para pausar la animación
// - En modo depuración nunca se hace la pausa (esto es para poder depurar el Three.js en el Three.js.inspector)
ObjetoCanvas.prototype.EventoPausa = function() { if (this.RAFID !== 0 && this.OpcionesCanvas.Pausar === true) { document.getElementById("Cabecera").setAttribute("animar", false); console.log("ObjetoCanvas.Pausa"); window.cancelAnimationFrame(this.RAFID); this.RAFID = 0; if (typeof this.Pausa !== 'undefined') { this.Pausa(); } }
};
// Función para reanudar la animación desde el ultimo punto
ObjetoCanvas.prototype.EventoReanudar = function() { if (this.RAFID === 0 && this.FocoWeb === true) { document.getElementById("Cabecera").setAttribute("animar", true); this.RAFID = window.requestAnimationFrame(this.Actualizar.bind(this)); console.log("ObjetoCanvas.Reanudar RAFID = " + this.RAFID); if (typeof this.Pausa !== 'undefined') { this.Reanudar(); } }
};
// Función que controla el scroll para determinar si la animación sigue a la vista o no y de esta forma detenerla / reanudarla
ObjetoCanvas.prototype.EventoScroll = function() { // Llamo a la función Scroll del NuevoObjeto (si existe) if (this.OpcionesCanvas.Entorno === "Banner") {
// if (this.Cabecera.length > 0) { // Hay páginas que no tienen la cabecera var PS = $(window).scrollTop(); var Altura = this.Cabecera.offsetHeight; if (PS > Altura) { this.EventoPausa(); } else if (PS < Altura) { this.EventoReanudar(); } } if (typeof(this.Scroll) !== "undefined") { this.Scroll.apply(this); }
};
// Función que cuenta los frames por segundo
ObjetoCanvas.prototype.FPS = function() { if (this.Tick > this.FPS_UltimoTick) { this.FPS_UltimoTick = this.Tick + 1000; document.getElementById("Cabecera_Stats").innerHTML = this.FPS_Contador + " FPS"; this.FPS_Contador = 0; } else { this.FPS_Contador ++; }
};
////////////////////////////////////////////////////////////////////////////
// Objeto que crea y contiene un canvas 2d para utilizarlo de back buffer //
////////////////////////////////////////////////////////////////////////////
var BufferCanvas = function(Ancho, Alto) { this.Canvas = document.createElement("canvas"); this.Canvas.setAttribute("width", Ancho); this.Canvas.setAttribute("height", Alto); this.Context = this.Canvas.getContext("2d"); this.Ancho = Ancho; this.Alto = Alto;
};
/* Función para generar un valor aleatório entero */
/* Si no se especifican parametros devuelve 0 o 1 */
/* Si solo se especifica un parámetro, el primer parámetro será el máximo, y el mínimo será 0 */
/* Si se especifican dos parámetros, el primero es el máximo, y el segundo es el mínimo. */
function RandInt(Max, Min) { return Math.floor(Rand(Max, Min));
}
/* Si no se especifican parametros devuelve 0 o 1 Si se especifica solo el Máximo, el mínimo será 0 */
function Rand(Max, Min) { var min = (typeof(Min) !== "undefined") ? Min : 0; // Si no se especifica el mínimo por defecto es 0 var max = (typeof(Max) !== "undefined") ? Max : 1; // Si no se especifica el máximo por defecto es 1 return min + Math.random() * (max - min);
}
/* Pequeño objeto que añade un enlace a mi pagina web en la parte inferior izquierda del ejemplo. */
var Logo_devildrey33 = function() { var PreLogo = document.createElement('a'); PreLogo.setAttribute("href", "http://devildrey33.es"); PreLogo.setAttribute("target", "_blank"); PreLogo.id = "Logo_devildrey33"; PreLogo.innerHTML = "<div>" + "<span>D</span>" + "<span>E</span>" + "<span>V</span>" + "<span>I</span>" + "<span>L</span>" + "<span>D</span>" + "<span>R</span>" + "<span>E</span>" + "<span>Y</span>" + "<span>&nbsp;</span>" + "<span>3</span>" + "<span>3</span>" + "</div>" + "<img src='http://devildrey33.es/Web/SVG/Iconos50x50.svg#svg-logo' />"; document.body.appendChild(PreLogo);
};
var Logo = null;
window.addEventListener('load', function() { Logo = new Logo_devildrey33; });
ObjetoCanvas y ObjetoLogo - Script Codes
ObjetoCanvas y ObjetoLogo - Script Codes
Home Page Home
Developer Josep Antoni Bover Comas
Username devildrey33
Uploaded August 27, 2022
Rating 3
Size 7,884 Kb
Views 28,336
Do you need developer help for ObjetoCanvas y ObjetoLogo?

Find the perfect freelance services for your business! Fiverr's mission is to change how the world works together. Fiverr connects businesses with freelancers offering digital services in 500+ categories. Find Developer!

Josep Antoni Bover Comas (devildrey33) Script Codes
Create amazing sales emails with AI!

Jasper is the AI Content Generator that helps you and your team break through creative blocks to create amazing, original content 10X faster. Discover all the ways the Jasper AI Content Platform can help streamline your creative workflows. Start For Free!