Agrega Custom Code en Wix sin Plan Premium 2025: Scroll Snap Effect
- Universal Web

- Oct 22
- 3 min read
En este tutorial te enseño cómo insertar custom code en Wix aunque tu sitio no tenga plan premium.
Verás cómo usar recursos externos y trucos de desarrollo para ampliar las funcionalidades de tu sitio con Wix Velo.
Perfecto para freelancers, creadores y desarrolladores que quieren probar código sin pagar hosting.
Agrega Custom Code en Wix sin Plan Premium 2025: Scroll Snap Effect

CSS CODE
.scroll-item {
height: 100vh; /* Ocupar toda la altura de la ventana */
display: flex;
}PAGE CODE
import { createCustomEmbed, listCustomEmbed, removeCustomEmbed } from 'backend/embed.web';
$w.onReady(async () => {
const html = `<style>
#SITE_CONTAINER {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
overflow: hidden;
scroll-behavior: smooth;
}
#masterPage {
width: 100%;
will-change: transform;
transition: transform 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
section {
height: 100vh;
width: 100%;
display: flex;
flex-direction: column;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
const scroller = document.querySelector('#masterPage');
const sections = document.querySelectorAll('section.scroll-item');
const speed = 1;
let currentSection = 0;
let isAnimating = false;
// Set initial transition duration
updateTransitionDuration();
function updateTransitionDuration() {
scroller.style.transition = "transform 1s cubic - bezier(0.25, 0.46, 0.45, 0.94)";
}
// Function to navigate to a specific section
function goToSection(index) {
if (isAnimating || index < 0 || index >= sections.length) return;
isAnimating = true;
currentSection = index;
// Calculate the transform value
const translateY = -index * 100;
scroller.style.transform = "translateY(" + translateY+ "vh)";
setTimeout(() => {
isAnimating = false;
}, parseFloat(speed) * 1000);
}
// Keyboard navigation
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown') {
goToSection(currentSection + 1);
e.preventDefault();
} else if (e.key === 'ArrowUp') {
goToSection(currentSection - 1);
e.preventDefault();
}
});
// Mouse wheel navigation with debouncing
let wheelTimeout;
document.addEventListener('wheel', (e) => {
clearTimeout(wheelTimeout);
wheelTimeout = setTimeout(() => {
if (e.deltaY > 50) {
goToSection(currentSection + 1);
} else if (e.deltaY < -50) {
goToSection(currentSection - 1);
}
}, 100);
}, { passive: true });
// Touch swipe support for mobile devices
let touchStartY = 0;
document.addEventListener('touchstart', (e) => {
touchStartY = e.changedTouches[0].screenY;
}, { passive: true });
document.addEventListener('touchend', (e) => {
const touchEndY = e.changedTouches[0].screenY;
const diffY = touchEndY - touchStartY;
if (Math.abs(diffY) > 50) {
if (diffY > 0) {
// Swiped down
goToSection(currentSection - 1);
} else {
// Swiped up
goToSection(currentSection + 1);
}
}
}, { passive: true });
});
</script>`;
const customEmbed = {
embedData: {
category: "ESSENTIAL",
html: html
},
position: "BODY_START",
name: "csscode"
}
const embeds = await listCustomEmbed();
console.log("embeds", embeds);
if (embeds.customEmbeds.length > 0) {
const embedFound = embeds.customEmbeds.filter((em) => em.name == "csscode");
if (embedFound.length == 0) {
const response = await createCustomEmbed(customEmbed);
console.log("repsonse", response);
}
} else {
const response = await createCustomEmbed(customEmbed);
}
});
Backend embed.web.js
import { customEmbeds } from "@wix/embeds";
import { auth } from "@wix/essentials";
import { Permissions, webMethod } from "wix-web-module";
export const createCustomEmbed = webMethod(
Permissions.Anyone,
async (customEmbed) => {
try {
const elevatedCreateCustomEmbed = auth.elevate(
customEmbeds.createCustomEmbed,
);
const response = await elevatedCreateCustomEmbed(customEmbed);
return response;
} catch (error) {
console.log(error);
}
}
);
export const listCustomEmbed = webMethod(
Permissions.Anyone,
async () => {
try {
const elevatedListCustomEmbeds = auth.elevate(customEmbeds.listCustomEmbeds);
const response = await elevatedListCustomEmbeds();
return response;
} catch (error) {
console.log(error);
}
}
);
export const removeCustomEmbed = webMethod(
Permissions.Anyone,
async (customEmbedId) => {
try {
const elevatedDeleteCustomEmbed = auth.elevate(
customEmbeds.deleteCustomEmbed,
);
const response = await elevatedDeleteCustomEmbed(customEmbedId)
} catch (error) {
console.log(error);
}
}
);


Hola como estas... si vi tu video del custom code, justo la semana pasada encontré esa api tambien en la documentacion, y la implemente en un ecommerce, mas que nada en el precio del producto con descuento..:
function actualizarPrecioTotal() {
const colorId = $w("#colorDropdown").value;
const medidaId = $w("#medidaDropdown").value;
const quantity = Number($w("#quantityInput").value) || 1;
const precioColor = PRECIOS_OPCIONES.colores[colorId] || 0;
const precioMedida = PRECIOS_OPCIONES.medidas[medidaId] || 0;
// ✅ Precio SIN descuento (para mostrar tachado)
const precioUnitarioOriginal = PRECIOS_OPCIONES.base + precioColor + precioMedida;
const precioTotalOriginal = precioUnitarioOriginal * quantity;
// ✅ Precio CON descuento (solo se aplica al precio base)
const precioUnitarioConDescuento = PRECIOS_OPCIONES.baseConDescuento + precioColor + precioMedida;
const precioTotalConDescuento = precioUnitarioConDescuento * quantity;
// ✅ Mostrar precio con formato según si hay descuento o no
if (PRECIOS_OPCIONES.descuento > 0) {
/* // Precio original tachado arriba, precio con descuento abajo
$w("#precioTotal").html = `
<div style="text-align: right;">
<p style="text-decoration: line-through; color: #999; margin: 0; font-size: 14px;">
$${precioTotalOriginal.toFixed(2)}
</p>
<p style="color: #e63946; font-weight: bold; margin: 0; font-size: 20px;">
$${precioTotalConDescuento.toFixed(2)}
</p>
<p style="color: #e63946;…