Disclaimer: I will be using Divi for this one because that’s what my site ended up having the most tutorials for, but this will work in any page builder as long as you use the equivalent module/block/widget.
I’ve seen this question asked a lot in the WP groups I frequent: “How do I take this codepen and use it on my site?”
The fb post I had started to help with was wondering about this pen in particular. https://codepen.io/suth_a/pen/ExbyvjK
And check out the working demo page here
So yeah, let’s break this down.
This tutorial will be aimed at beginners who are not as well versed in all the languages and how they work together. I’ll explain the basics here.
HTML5, or the language of modern websites, are basically made with 3 different coding languages (or script, or markup, depending on who you ask) HTML, CSS, and JavaScript.
HTML is the basic structure. It’s what wraps the content so the other two languages can find their places. CSS is what makes the design. It gives instructions on how the HTML should be displayed. JS is what gives it interactivity. JS can detect what the user is doing and react accordingly.
All three have advanced syntaxes that people have put together so it’s easier to write, but usually needs a compiler for it to render.
Common ones are like HAML or even the Emmet plugin for writing quick HTML, and SASS, SCSS, (which you can learn here) or LESS can be compiled into CSS, and there are tons of JS libraries that allow you to write for certain things more easily than just vanilla JS, such as jQuery or Svelte, and to get into special purpose libraries, GSAP, MagicScroll, etc. So you load the library, and write the JS that uses that library. (Node, React, and Angular are more full stack-y, so I didn’t include them in this quick list)
OK. That’s enough background info. Let’s get into the pen itself.
Watch the video below, or just keep reading to see it in written step-by-step form.
Looking at the pen, you will see three windows on top.
- Left: HTML
- Center: CSS
- Right: JS
(Remember the three web languages?)
So, what you’re seeing there is the HTML structure needed for the JS to find the target and do its thing. The CSS style sheet that allows the space to be large enough to work, and the JS itself.
We can start easily by adding the html to a code module, and if you don’t want to add the CSS site-wide then just drop it inside style tags.
BUT, remember, in order for any non-vanilla JS to work, you’d need to load the library first. So, check out what’s been loaded by clicking on the small cog on top of the JS window. Ah, GSAP, JQ, and Physics2D. We’ll need to load those too.
To load a JS library, usually the GitHub page or wherever it lives will have something like a cdn link you can use to enqueue it in WP.
(Note: cdn links are good because if it’s a popular library like jQuery or GSAP, chances are users will already have it cached in their computers, so your load times will reap the benefits. But it will cause problems if the site has to be accessed from China due to the Great Firewall, so just keep that in mind.)
Here’s how you enqueue it in WP. (If you’re using a child theme or a custom plugin, and you can edit the functions.php file) This will apply site-wide.
/* This should be INSIDE the php file inside the php declarations */
add_action('wp_footer', 'your_function_nametwo');
function your_function_nametwo(){
wp_enqueue_script( 'jquery00', 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js' );
};
Here’s how you add it via html. (In a code module, or just in the theme settings) If it’s in a code module, it’ll just apply to that page. If you add it in the footer, then it’ll be site-wide.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
In the case of this pen, load all three libraries. (NOTE: I just realized this after trying this live, that the physics2D doesn’t work without a GSAP membership (it’s a premium library) so just the first two..)
Then add the JS inside a script tag.
To put everything into ONE code module here’s what you can copy paste into a code module:
<div id="panel">
<canvas id="magic-dust"></canvas>
</div>
<style>
#panel {
width: 100%;
height: 100vh;
background-color: #000;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
var end_panel = document.querySelector("#panel");
var end_cv = document.getElementById("magic-dust");
var end_ctx = end_cv.getContext("2d");
var end_cvWidth = parseInt(window.getComputedStyle(end_panel).width, 10); // get width without "px"
var end_cvHeight = parseInt(window.getComputedStyle(end_panel).height, 10); // get height without "px"
var resolution = window.devicePixelRatio || 1;
var sprites = [];
var toRad = Math.PI / 180;
var fx_tl;
// resize for retina
resizeCv();
function start_fx() {
// particles
init_fx(
"circle", // texture
1777, // total sprites
50,50, 50,50, // width-+, height-+
0,1600, 0,1600, // start position x-+, y-+
4,12, 0,360, // velocity-+, angle-+
.1,2.5, .2,.8, // scale start-+, end-+
360, 0,0, // rotation start, end-+
1.7,24, // duration-+
.1, 2, // fade in, out duration
0.1, // gravity
12, // delay+ inbetween sprites
-1, // repeat sprite animation (-1 = infinite)
0 // delay timeline
);
}
$(document).mousemove(function(e) {
var x = e.pageX;
var y = e.pageY;
var scrollPosition = $(window).scrollTop()
createMagicDust(x,y-scrollPosition,5)
});
function init_fx(textureSpr, totalSpr, minWidth,maxWidth, minHeight,maxHeight, xMin,xMax, yMin,yMax, veloMin,veloMax, angleMin,angleMax, startScaleMin,startScaleMax, endScaleMin,endScaleMax, rotStart, rotEndMin,rotEndMax, minDur,maxDur, fadeInDur, fadeOutDur, gravitySpr, delaySpr, repeatSpr, delayTl) {
// generate sprites
for (var i = 0; i < totalSpr; i++) {
var widthSpr = randomInt(minWidth, maxWidth);
var heightSpr = randomInt(minHeight, maxHeight);
// define texture
var texture = createShape(textureSpr, i);
sprites.push(createSprite());
}
createMagicDust = (x,y,n) => {
for (var i = 0; i < n; i++) {
var texture = createShape(textureSpr, Math.floor(Math.random()*10));
sprites.push(createSprite(x,y,2));
}
};
// start rendering animation
gsap.ticker.add(renderCv);
gsap.registerPlugin(Physics2DPlugin);
function createSprite(x,y,t) {
var width = (texture.naturalWidth || texture.width || 0) / resolution;
var height = (texture.naturalHeight || texture.height || 0) / resolution;
var duration = t || randomNr(minDur, maxDur);
// limit angle if needed
var angleNr;
if (angleMin == -90 && angleMax == -270) {
angleNr = Math.random() < 0.5 ? 90 : 270; // only up or down
} else if (angleMin == -0 && angleMax == -180) {
angleNr = Math.random() < 0.5 ? 0 : 180; // only left or right
} else {
angleNr = randomNr(angleMin, angleMax);
}
// create a new timeline for the sprite
fx_tl = gsap.timeline({
delay: t ? 0 : randomNr(delaySpr),
repeat: t ? 0 : repeatSpr,
repeatDelay: randomNr(1)
});
// sprite object default properites
var sprite = {
animation: fx_tl,
texture: texture,
width: width,
height: height,
alpha: 0,
rotation: randomNr(rotStart),
scale: randomNr(startScaleMin, startScaleMax),
originX: t ? .2 : 0.5,
originY: t ? .3 : 0.5,
x: x || randomNr(xMin, xMax),
y: y || randomNr(yMin, yMax),
};
// animate to
fx_tl.add("start", delayTl)
.to(sprite, t ? 0.3 : fadeInDur, {alpha: 1, ease:Power0.easeIn}, "start")
.to(sprite, duration, {
rotation: 180 * randomNr(rotEndMin, rotEndMax),
scale: randomNr(endScaleMin, endScaleMax),
physics2D: {
velocity: randomNr(veloMin, veloMax),
angle: angleNr,
gravity: gravitySpr,
}
}, "start")
// fade out
.to(sprite, t ? 1.5 : fadeOutDur, {
alpha: 0,
delay: t ? 1.5 : duration-fadeOutDur
}, 0);
return sprite;
}
function createShape(textureSpr, i) {
// Create offscreen canvas
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
canvas.width = widthSpr * resolution;
canvas.height = heightSpr * resolution;
var radius = widthSpr / 2;
var gradient = context.createRadialGradient(radius, radius, 0, radius, radius, radius);
if (i % 3 === 0){
gradient.addColorStop(0, "rgba(177,255,252,0.75)");
gradient.addColorStop(0.15, "rgba(177,255,252,0.1)");
} else if (i % 5 === 0){
gradient.addColorStop(0, "rgba(202,76,255,0.6)");
gradient.addColorStop(0.1, "rgba(202,76,255,0.1)");
} else {
gradient.addColorStop(0, "rgba(102,219,214,0.6)");
gradient.addColorStop(0.1, "rgba(102,219,214,0.1)");
}
gradient.addColorStop(0.65, "rgba(0,0,0,0)");
context.fillStyle = gradient;
context.fillRect(0, 0, widthSpr, heightSpr);
return canvas;
}
}
function renderCv() {
end_ctx.clearRect(0, 0, end_cvWidth, end_cvHeight);
for (var i = 0; i < sprites.length; i++) {
var sprite = sprites[i];
// Skip rendering sprite if it has no alpha
if (!sprite.alpha) {
continue;
}
end_ctx.save();
var offsetX = sprite.originX * sprite.width;
var offsetY = sprite.originY * sprite.height;
end_ctx.translate(sprite.x + offsetX, sprite.y + offsetY);
end_ctx.rotate(sprite.rotation * toRad);
end_ctx.scale(sprite.scale, sprite.scale);
end_ctx.globalAlpha = sprite.alpha;
end_ctx.drawImage(sprite.texture, -offsetX, -offsetY);
end_ctx.restore();
}
}
function resizeCv() {
end_cv.width = end_cvWidth * resolution;
end_cv.height = end_cvHeight * resolution;
end_cv.style.width = end_cvWidth + "px";
end_cv.style.height = end_cvHeight + "px";
end_ctx.scale(resolution, resolution);
}
function randomNr(min, max) {
if (max === undefined) { max = min; min = 0; }
if (min > max) { var tmp = min; min = max; max = tmp; }
return min + (max - min) * Math.random();
}
function randomInt(min, max) {
if (max === undefined) { max = min; min = 0; }
if (min > max) { var tmp = min; min = max; max = tmp; }
return Math.floor(min + (max - min + 1) * Math.random());
}
start_fx();
</script>
And there you go.🙂
All done.
Extra notes:
GSAP has a membership that allows you to use all the libraries, you’ll need that to get the third one to work. The only difference is the stars don’t float as nicely.
Every page builder (including Gutenberg) has a code module. NOT a code display module (like a <pre>) but a direct html module. Use that.
Matt says:
Hi PK,
Can you please explain how to target specific sections/rows with this code?
e.g. if I want to use this as a section backgound, let’s say class=”et_pb_section_1″
I’m sure it’s easy but im a total noob. Thanks!
Matt
Terry Hale says:
Hey, PK! Thanks so much for taking the time to write this up for us. Good stuff!
If I may, it would be great if your code wasn’t such a large font. Also, I’d be interesting in hearing what you are using to present code. Especially with the large font, a ‘copy’ button on the code would be great. I’m using the Prismatic plugin for WordPress and absolutely love it.
Thanks again, this is great, and also thanks for all your help in the FB groups!
ChikQ says:
Hi PK, thank you so much for this tutorial. I am simply dangerous enough with HTML. With CSS and Javascript, I’m a complete noob. I was provided a codepen by a vender with a “here you go, good luck” message. Thanks to your tutorial, I was able to implement it successfully. In addition to the general input of the code, the gamechanger was adding the source code first. Again, thank you!
Jared says:
Hey, do I need to enqueue the library in the functions.php file AND add the cdn link as the src of a script tag, or do I just do one or the other?
Thanks!