HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by esm.sh, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ESM usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
html, body, canvas {
margin: 0px;
height: 100%;
width: 100%;
overflow: hidden;
}
(function () {
var setting = {
electronBaseSpeed: 0.05,
electronRandomSpeed: 0.01,
numberOfElectrons: 200,
numberOfNeighbours: 15
},
// global variables
canvas, ctx, width, height, ox, oy, mouseX = 0, mouseY = 0,
heart = [], electron = [];
/*
Heart data used from this 3d model found online.
- http://www.gameartmarket.com/details?id=ag9zfmRhZGEtM2RtYXJrZXRyMgsSBFVzZXIiE3BpZXJ6YWtAcGllcnphay5jb20MCxIKVXNlclVwbG9hZBjX1sjl-ScM
I added a few points and scaled the heart along one dimension to make it less 'fat' than before.
This string of numbers is the serialized point data from an .X3D export using blender.
*/
var pointData = "32.7292 25.3718 43.2941 21.0824 36.5664 57.2912 0 27.3696 39.0791 0 26.9858 60.5122 0 2.32386 60.836 23.9945 4.97553 43.9781 23.9945 4.7544 56.3249 21.0824 36.8403 41.9962 32.7292 25.1378 56.3585 16.7785 -5.49356 50.3167 8.93792 37.3095 49.634 18.8047 18.6138 37.4886 8.38923 -6.68778 55.9632 1.51521 -17.7438 50.5677 34.0204 16.3753 49.9679 8.38923 -6.48615 44.7051 18.8047 18.1679 62.3829 32.5001 34.5348 49.6783 30.2165 17.023 41.9277 14.6811 -5.83143 53.9235 10.3525 34.4104 60.2188 5.58722 -13.1681 50.4391 36.2585 26.7705 49.8021 10.3525 34.788 39.1357 0 29.5792 49.7573 0 13.515 63.157 14.6811 -5.70239 46.7186 30.2165 16.7353 57.9921 27.2874 5.05264 50.1485 14.116 4.47563 40.4627 14.116 4.12825 59.8583 28.9508 30.6739 39.9656 28.9508 30.3237 59.5197 22.3116 40.7303 49.5795 -14.6811 -5.70239 46.7186 -16.7785 -5.49356 50.3167 -5.58722 -13.1681 50.4391 -23.9945 4.97553 43.9781 -27.2874 5.05264 50.1485 -23.9945 4.7544 56.3249 -14.6811 -5.83143 53.9235 -21.6175 37.3353 41.9883 -10.3525 34.788 39.1357 -8.93792 37.3095 49.634 -22.8466 41.2253 49.5716 -10.3525 34.4104 60.2188 -21.6175 37.0614 57.2833 -18.8047 18.6138 37.4886 0 13.986 36.8626 -28.9508 30.6739 39.9656 -32.7292 25.3718 43.2941 -30.2165 17.023 41.9277 -14.116 4.47563 40.4627 0 2.70524 39.542 0 -19.2088 50.6313 -1.51521 -17.7438 50.5677 -8.38923 -6.68778 55.9632 0 -7.24557 56.5913 -14.116 4.12825 59.8583 0 -7.02175 44.0944 -8.38923 -6.48615 44.7051 -34.0204 16.3753 49.9679 -36.2585 26.7705 49.8021 -32.7292 25.1378 56.3585 -30.2165 16.7353 57.9921 -18.8047 18.1679 62.3829 -28.9508 30.3237 59.5197 -32.5001 34.5348 49.6783"
;
// create Math.sin lookup table (cos == sin+90)
var r = [];
for (var i = 0; i < 720; i++)
r.push(Math.sin(i * (Math.PI / 180)));
// rotate a point about origin in 3d space
function rotate(p, x, y, z) {
var u, v, w, h = p.x * r[z+90] - p.y * r[z];
z = p.x * r[z] + p.y * r[z+90];
u = p.z * r[y+90] - h * r[y];
v = p.z * r[y] + h * r[y+90];
h = z * r[x+90] - u * r[x];
w = z * r[x] + u * r[x+90];
return { x: v, y: h, z: w, p: p.p };
};
// find the closest neighbours in the network to the specified point
function findNeighbours(p, data) {
var t = [];
for (var i = 0; i < data.length; i++)
t.push({
i: i,
d: distanceBetweenPoints(data[i], data[p])
});
t.sort(function(p1, p2) {
return p1.d - p2.d;
});
return t.slice(1, 1 + setting.numberOfNeighbours).map(function(e) {
return e.i;
});
}
function nthroot(x, n) {
// This function borrowed from http://stackoverflow.com/questions/7308627/javascript-calculate-the-nth-root-of-a-number
try {
var negate = n % 2 == 1 && x < 0;
if(negate)
x = -x;
var possible = Math.pow(x, 1 / n);
n = Math.pow(possible, n);
if(Math.abs(x - n) < 1 && (x > 0 == n > 0))
return negate ? -possible : possible;
} catch(e) {}
}
function distanceBetweenPoints(p1, p2) {
return nthroot(
(
(p2.x - p1.x) * (p2.x - p1.x) +
(p2.y - p1.y) * (p2.y - p1.y) +
(p2.z - p1.z) * (p2.z - p1.z)
), 3);
}
function deserializeHeartData() {
var d = [],
r = pointData.split(' ');
function roundScalar(p) {
return Math.round(parseFloat(p) * 8);
}
for (var i = 0, j = 0; i < r.length; j++) {
var t = {
x: roundScalar(r[i++]),
y: roundScalar(r[i++]) - 115, // these constants to center the object
z: roundScalar(r[i++]) - 400
};
d.push(t);
}
for (var i = 0; i < d.length; i++)
d[i].p = {
i: i,
n: findNeighbours(i, d)
};
return d;
}
function init() {
// create canvas
canvas = document.createElement('canvas');
height = canvas.height = document.body.clientHeight - 1;
width = canvas.width = document.body.clientWidth - 1;
// setup origin
ox = width / 2;
oy = height / 2;
// append to DOM and set some defaults
document.body.appendChild(canvas);
ctx = canvas.getContext('2d');
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
// initial instant paint of background
ctx.fillStyle = 'rgba(0,0,0,1)';
ctx.fillRect(0, 0, width, height);
// deserialize heart from X3D model data
heart = deserializeHeartData();
for (var i = 0; i < setting.numberOfElectrons; i++) {
var j = ~~(Math.random() * heart.length);
electron.push({ p1: j, p2: heart[j].p.n[0], d: 0, s: Math.random() * setting.electronBaseSpeed + setting.electronRandomSpeed });
}
// start our animation
window.requestAnimationFrame(render);
}
function distanceOpacity(z, zmin, zmax) {
return Math.min(1, Math.max(0, (z - zmin) / (zmax - zmin)));
}
function render() {
ctx.shadowColor = 'rgba(0,0,0,0)';
ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.fillRect(0, 0, width, height);
// create new 3d point array
var rotated = [];
// populate array with data from initial state, but rotated required amount
for (i = 0; i < heart.length; i++) {
var f = rotate(heart[i], ~~(180 - 70 * mouseY), ~~(180 - 50 * mouseX), 0);
rotated.push(f);
}
// sort the points by z-value
rotated.sort(function(p1, p2) {
return p1.z - p2.z;
});
// update mapping to renderable from the original data
for (i = 0; i < rotated.length; i++) {
heart[rotated[i].p.i].p.o = i;
}
for (i = 0; i < electron.length; i++) {
var p1 = rotated[heart[electron[i].p1].p.o],
p2 = rotated[heart[electron[i].p2].p.o],
ex = ((p2.x - p1.x) * electron[i].d) + p1.x,
ey = ((p2.y - p1.y) * electron[i].d) + p1.y,
ez = ((p2.z - p1.z) * electron[i].d) + p1.z;
var rad = 6;
ctx.beginPath();
ctx.shadowColor = 'rgba(255,80,80,' + distanceOpacity(ez, -200, 100) + ')';
ctx.arc(ox + ex, oy + ey, rad, 0, Math.PI * 2, false);
ctx.closePath();
var radial = ctx.createRadialGradient(ox + ex, oy + ey, 0, ox + ex, oy + ey, rad);
radial.addColorStop(0,'rgba(255,120,220,' + distanceOpacity(ez, -200, 220) + ')');
radial.addColorStop(0.6,'rgba(145,0,100,' + distanceOpacity(ez, -200, 220) + ')');
radial.addColorStop(1,'rgba(40,0,0,' + distanceOpacity(ez, -200, 480) + ')');
ctx.fillStyle = radial;
ctx.fill();
electron[i].d += electron[i].s;
if (electron[i].d >= 1) {
electron[i].d = 0;
electron[i].p1 = electron[i].p2;
electron[i].p2 = heart[electron[i].p2].p.n[
~~(heart[electron[i].p2].p.n.length * Math.random())
];
electron[i].s = Math.random() * setting.electronBaseSpeed + setting.electronRandomSpeed;
}
}
// render the points, starting furthest to closest
ctx.shadowBlur = 33;
for (i = 0; i < rotated.length; i++) {
var rad = 15;
ctx.beginPath();
ctx.shadowColor = 'rgba(255,80,80,' + distanceOpacity(rotated[i].z, -200, 100) + ')';
ctx.arc(ox + rotated[i].x, oy + rotated[i].y, rad, 0, Math.PI * 2, false);
ctx.closePath();
var radial = ctx.createRadialGradient(ox + rotated[i].x, oy + rotated[i].y, 0, ox + rotated[i].x, oy + rotated[i].y, rad);
radial.addColorStop(0,'rgba(255,20,20,' + distanceOpacity(rotated[i].z, -200, 220) + ')');
radial.addColorStop(0.6,'rgba(245,0,0,' + distanceOpacity(rotated[i].z, -200, 220) + ')');
radial.addColorStop(1,'rgba(100,0,0,' + distanceOpacity(rotated[i].z, -200, 380) + ')');
ctx.fillStyle = radial;
ctx.fill();
}
ctx.font='142px x';
ctx.fillStyle='#fff';
ctx.fillText('愛老虎油' , ox - 270, oy + 230);
window.requestAnimationFrame(render);
}
window.onload = init;
window.onmousemove = function(e) {
mouseX = (e.pageX - ox) / width;
mouseY = (e.pageY - oy) / height;
};
})();
Also see: Tab Triggers