circle intersection
96
docs/chapters/circleintersection/circle.js
Normal file
@@ -0,0 +1,96 @@
|
||||
import refineBinary from "../projections/refine-binary.js";
|
||||
|
||||
let curve;
|
||||
|
||||
setup() {
|
||||
curve = Bezier.defaultCubic(this);
|
||||
setMovable(curve.points);
|
||||
setSlider(`.slide-control`, `radius`, 102);
|
||||
}
|
||||
|
||||
draw() {
|
||||
clear();
|
||||
curve.drawSkeleton(`lightblue`);
|
||||
curve.drawCurve();
|
||||
curve.drawPoints();
|
||||
|
||||
noFill();
|
||||
let x = this.width/2;
|
||||
let y = this.height/2;
|
||||
|
||||
// Find all the circle intersections for this curve:
|
||||
let LUT = curve.getLUT(100);
|
||||
let start = 0, count = 0;
|
||||
let values = [];
|
||||
|
||||
// never use while(true)
|
||||
while(++count < 25) {
|
||||
let i = start + this.findClosest(
|
||||
x, y, LUT.slice(start),
|
||||
// We also want the previous two distances, which either don't
|
||||
// exist because we're starting at 0, or they exist because they
|
||||
// were computed in the previous findClosest() call.
|
||||
LUT[start-2]?.distance,
|
||||
LUT[start-1]?.distance
|
||||
);
|
||||
if (i < start) break;
|
||||
if (i>0 && i === start) break;
|
||||
values.push(i);
|
||||
start = i + 2; // We need to add 2, because findClosest already tells us that i+1 cannot be a viable candidate.
|
||||
}
|
||||
|
||||
// Draw a convenience marker for our circle center
|
||||
setStroke(`black`);
|
||||
line(x-10,y,x+10,y);
|
||||
line(x,y-10,x,y+10);
|
||||
|
||||
// Then draw our circle, and all intersections
|
||||
setStroke(values.length ? `green` : `red`);
|
||||
circle(x, y, this.radius);
|
||||
values.forEach(i => this.drawProjection(x, y, LUT, i));
|
||||
}
|
||||
|
||||
// We want to find the "locally closest" points, rather than
|
||||
// the globally closest point, so we don't run a blind .forEach
|
||||
// as in the projection graphic, but instead find a value of i
|
||||
// such that the distance for [i-1] and [i+1] are both bigger
|
||||
// than for [i], signalling a local minimum.
|
||||
findClosest(x, y, LUT, pd2, pd1, distanceEpsilon = 5) {
|
||||
let distance = Number.MAX_SAFE_INTEGER,
|
||||
prevDistance2 = pd2 || distance,
|
||||
prevDistance1 = pd1 || distance,
|
||||
i = -1;
|
||||
|
||||
for(let index=0, e=LUT.length; index<e; index++) {
|
||||
let p = LUT[index];
|
||||
p.distance = abs(dist(x, y, p.x, p.y) - this.radius);
|
||||
|
||||
// Realistically, there's only going to be an intersection if
|
||||
// the distance to the circle center is already approximately
|
||||
// the circle's radius.
|
||||
if (prevDistance1 < distanceEpsilon && prevDistance2 > prevDistance1 && prevDistance1 < p.distance) {
|
||||
i = index - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p.distance < distance) {
|
||||
distance = p.distance;
|
||||
}
|
||||
|
||||
prevDistance2 = prevDistance1;
|
||||
prevDistance1 = p.distance;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
drawProjection(x, y, LUT, i) {
|
||||
let B = refineBinary(curve, x, y, LUT, i, this.radius);
|
||||
setColor(`rgba(100,100,255)`);
|
||||
circle(B.x, B.y, 3);
|
||||
line(B.x, B.y, x, y);
|
||||
}
|
||||
|
||||
onMouseMove() {
|
||||
redraw();
|
||||
}
|
92
docs/chapters/circleintersection/content.en-GB.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Intersections with a circle
|
||||
|
||||
It might seem odd to cover this subject so much later than the line/line, line/curve, and curve/curve intersection topics from several sections earlier, but the reason we can't cover circle/curve intersections is that we can't really discuss circle/curve intersection until we've covered the kind of lookup table (LUT) walking that the section on projecting a point onto a curve uses. To see why, let's look at what we would have to do if we wanted to find the intersections between a curve and a circle using calculus.
|
||||
|
||||
First, we observe that "finding intersections" in this case means that, given a circle defined by a center point `c = (x,y)` and a radius `r`, we want to find all points on the Bezier curve for which the distance to the circle's center point is equal to the circle radius, which by definition means those points lie on the circle, and so count as intersections. In maths, that means we're trying to solve:
|
||||
|
||||
\[
|
||||
dist(B(t), c) = r
|
||||
\]
|
||||
|
||||
Which seems simple enough. Unfortunately, when we expand that `dist` function, things get a lot more problematic:
|
||||
|
||||
\[
|
||||
\begin{array}{cl}
|
||||
r &= dist(B(t), c) \\
|
||||
&= \sqrt{ \left ( B_x{t} - c_x \right )^2 + \left ( B_y{t} - c_y \right )^2} \\
|
||||
&= \sqrt{ \left (
|
||||
x_1 (1-t)^3 + 3 x_2 (1-t)^2 t + 2 x_3 (1-t) t^2 + x_4 t^3 - c_x
|
||||
\right )^2
|
||||
+
|
||||
\left (
|
||||
y_1 (1-t)^3 + 3 y_2 (1-t)^2 t + 2 y_3 (1-t) t^2 + y_4 t^3 - c_y
|
||||
\right )^2}
|
||||
\end{array}
|
||||
\]
|
||||
|
||||
And now we have a problem because that's a sixth degree polynomial inside the square root. So, thanks to the [Abel-Ruffini theorem](https://en.wikipedia.org/wiki/Abel%E2%80%93Ruffini_theorem) that we saw before, we can't solve this by just going "square both sides because we don't care about signs"... we can't solve a sixth degree polynomial. So, we're going to have to actually evaluate that expression. We can "simplify" this by translating all our coordinates so that the center of the circle is (0,0) and all our coordinates are shifted accordingly, which makes the c<sub>x</sub> and c<sub>y</sub> terms fall away, but then we're still left with a monstrous function to solve.
|
||||
|
||||
So instead, we turn to the same kind of "LUT walking" that we saw for projecting points onto a curve, with a twist: instead of finding the on-curve point with the smallest distance to our projection point, we want to find the on-curve point that has the exact distance `r` to our projection point (namely, our circle center). Of course, there can be more than one such point, so there's also a bit more code to make sure we find all of them, but let's look at the steps involved:
|
||||
|
||||
```
|
||||
c = our circle's center point
|
||||
r = our circle's radius
|
||||
d = some initially huge value
|
||||
i = 0
|
||||
for (coordinate, index) in LUT:
|
||||
q = abs(distance(coordinate, p) - r)
|
||||
if q < d:
|
||||
d = q
|
||||
i = index
|
||||
```
|
||||
|
||||
This is _very_ similar to the code in the previous section, but adapted so that we home in on points with an exact distance, rather than "the smallest distance". So far so good. However, we also want to make sure we find _all_ the points, not just a single one, so we need a little more code for that:
|
||||
|
||||
```
|
||||
c = our circle's center point
|
||||
r = our circle's radius
|
||||
d = some initially huge value
|
||||
start = 0
|
||||
values = []
|
||||
run:
|
||||
i = findClosest(start, x, y, r, LUT)
|
||||
if (i < start) stop
|
||||
if (i>0 && i === start) stop
|
||||
values.add(i);
|
||||
start = i + 2;
|
||||
```
|
||||
|
||||
After running this code, `values` will be the list of all LUT coordinates that are closest to the distance `r`: we can use those values to run the same kind of refinement lookup we used for point projection (with the caveat that we're now _not_ checking for smallest distance, but for "distance closest to `r`"), and we'll have all our intersection points. Of course, that does require explaining what `findClosest` does: rather than looking for a global minimum, we're now interested in finding a _local_ minimum, so instead of checking a single point and looking at its distance value, we check _three_ points ("current", "previous" and "before previous") and then check whether they form a local minimum:
|
||||
|
||||
```
|
||||
findClosest(start, x, y, r, LUT):
|
||||
D = some very large number
|
||||
pd2 = LUT[start-2], if it exists. Otherwise use D
|
||||
pd1 = LUT[start-1], if it exists. Otherwise use D
|
||||
slice = LUT.subset(start, LUT.length)
|
||||
epsilon = the largest point-to-point distance in our LUT
|
||||
i = -1;
|
||||
|
||||
for (point, index) in slice:
|
||||
q = abs(dist(point, (x,y)) - r);
|
||||
if pd1 < epsilon && pd2 > pd1 && pd1 < q:
|
||||
i = index - 1
|
||||
break
|
||||
|
||||
if q < D: D = q
|
||||
|
||||
pd2 = pd1
|
||||
pd1 = q
|
||||
|
||||
return start + i
|
||||
```
|
||||
|
||||
In words: given a `start` index, the circles `x`, `y`, and `r` values, and our LUT, we check where, closest to out `start` index, we can find a local minimum for the difference between the distance to the circle center, and the circle's radius value. We track this over three points, and we know we've found a local minimum if the distances `{pd2, pd1, index}` show that the middle value (`pd1`) is lower than the values on either side. When we do, we can set our "best guess related to `start`" as the index that belongs to that `pd1`. Of course, since we're not checking values relative to some `start` value, we might not find another candidate value at all, in which case we return `start - 1`, so that a simple "is the result less than `start`?" lets us determine that there are no more intersections to find.
|
||||
|
||||
So, the following graphic shows this off for the standard cubic curve (which you can move the coordinates around for, of course) and a circle with a controllable radius centered on the graphic's center, using the code approach described above.
|
||||
|
||||
<graphics-element title="circle intersection" src="./circle.js">
|
||||
<input type="range" min="1" max="150" step="1" value="70" class="slide-control">
|
||||
</graphics-element>
|
||||
|
||||
And of course, for the full details, click that "view source" link.
|
@@ -1,3 +1,5 @@
|
||||
import refineBinary from "./refine-binary.js";
|
||||
|
||||
let curve;
|
||||
|
||||
setup() {
|
||||
@@ -61,56 +63,12 @@ showCandidateInterval(x, y, LUT, i) {
|
||||
}
|
||||
|
||||
drawProjection(x, y, LUT, i) {
|
||||
let B = this.refineBinary(x, y, LUT, i);
|
||||
let B = refineBinary(curve, x, y, LUT, i);
|
||||
setColor(`rgba(100,100,255)`);
|
||||
circle(B.x, B.y, 3);
|
||||
line(B.x, B.y, x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
We already know that LUT[i1] and LUT[i2] are *not* good distances,
|
||||
so we know that a better distance will be somewhere between them.
|
||||
We generate three new points between those two, so we end up with
|
||||
five points, and then check which three of those five are a new,
|
||||
better, interval to check within.
|
||||
*/
|
||||
refineBinary(x, y, LUT, i) {
|
||||
let q, count=1, distance = Number.MAX_SAFE_INTEGER;
|
||||
|
||||
do {
|
||||
let i1 = i === 0 ? 0 : i-1,
|
||||
i2 = i === LUT.length - 1 ? LUT.length -1 : i+1,
|
||||
t1 = LUT[i1].t,
|
||||
t2 = LUT[i2].t,
|
||||
lut = [],
|
||||
step = (t2 - t1)/5;
|
||||
|
||||
if (step < 0.001) break;
|
||||
|
||||
lut.push(LUT[i1]);
|
||||
for(let j=1; j<=3; j++) {
|
||||
let n = curve.get(t1 + j *step);
|
||||
n.distance = dist(n.x, n.y, x, y);
|
||||
if (n.distance < distance) {
|
||||
distance = n.distance;
|
||||
q = n;
|
||||
i = j;
|
||||
}
|
||||
lut.push(n);
|
||||
}
|
||||
lut.push(LUT[i2]);
|
||||
|
||||
// update the LUT to be our new five point LUT, and run again.
|
||||
LUT = lut;
|
||||
|
||||
// The "count" test is mostly a safety measure: it will
|
||||
// never kick in, but something that _will_ terminate is
|
||||
// always better than while(true). Never use while(true)
|
||||
} while (count++ < 25);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
onMouseMove() {
|
||||
redraw();
|
||||
}
|
||||
|
55
docs/chapters/projections/refine-binary.js
Normal file
@@ -0,0 +1,55 @@
|
||||
function abs(v) {
|
||||
return v<0 ? -v : v;
|
||||
}
|
||||
|
||||
function dist(x1,y1,x2,y2) {
|
||||
return ((x1-x2)**2 + (y2-y1)**2) ** 0.5;
|
||||
}
|
||||
|
||||
/*
|
||||
We already know that LUT[i1] and LUT[i2] are *not* good distances,
|
||||
so we know that a better distance will be somewhere between them.
|
||||
We generate three new points between those two, so we end up with
|
||||
five points, and then check which three of those five are a new,
|
||||
better, interval to check within.
|
||||
*/
|
||||
function refineBinary(curve, x, y, LUT, i, targetDistance=0) {
|
||||
let q = LUT[i],
|
||||
count = 1,
|
||||
distance = Number.MAX_SAFE_INTEGER;
|
||||
|
||||
do {
|
||||
let i1 = i === 0 ? 0 : i - 1,
|
||||
i2 = i === LUT.length - 1 ? LUT.length - 1 : i + 1,
|
||||
t1 = LUT[i1].t,
|
||||
t2 = LUT[i2].t,
|
||||
lut = [],
|
||||
step = (t2 - t1) / 5;
|
||||
|
||||
if (step < 0.001) break;
|
||||
|
||||
lut.push(LUT[i1]);
|
||||
for (let j = 1; j <= 3; j++) {
|
||||
let n = curve.get(t1 + j * step);
|
||||
n.distance = abs(dist(n.x, n.y, x, y) - targetDistance);
|
||||
if (n.distance < distance) {
|
||||
distance = n.distance;
|
||||
q = n;
|
||||
i = j;
|
||||
}
|
||||
lut.push(n);
|
||||
}
|
||||
lut.push(LUT[i2]);
|
||||
|
||||
// update the LUT to be our new five point LUT, and run again.
|
||||
LUT = lut;
|
||||
|
||||
// The "count" test is mostly a safety measure: it will
|
||||
// never kick in, but something that _will_ terminate is
|
||||
// always better than while(true). Never use while(true)
|
||||
} while (count++ < 25);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
export default refineBinary;
|
@@ -47,6 +47,7 @@ export default [
|
||||
'abc',
|
||||
'pointcurves',
|
||||
'projections',
|
||||
'circleintersection',
|
||||
'molding',
|
||||
'curvefitting',
|
||||
|
||||
|
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,3 @@
|
||||
\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math
|
||||
|
||||
dist(B(t), c) = r
|
@@ -0,0 +1,11 @@
|
||||
\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math
|
||||
|
||||
r = dist(B(t), c)
|
||||
┌─────────────────────────┐
|
||||
│ 2 2
|
||||
= │(B t - c ) + (B t - c )
|
||||
⟍│ x x y y
|
||||
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│╭ 3 2 2 3 ╮2 ╭ 3 2 2 3 ╮2
|
||||
= ││ x (1-t) + 3 x (1-t) t + 2 x (1-t) t + x t - c │ + │ y (1-t) + 3 y (1-t) t + 2 y (1-t) t + y t - c │
|
||||
⟍│╰ 1 2 3 4 x ╯ ╰ 1 2 3 4 y ╯
|
@@ -0,0 +1,6 @@
|
||||
\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math
|
||||
|
||||
┌─────────────────────────┐
|
||||
│ 2 2
|
||||
dist(B(t), c = r │(B t - c ) + (B t - c ) = r
|
||||
⟍│ x x y y
|
@@ -0,0 +1,11 @@
|
||||
\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math
|
||||
|
||||
r = dist(B(t), c = r
|
||||
┌─────────────────────────┐
|
||||
│ 2 2
|
||||
= │(B t - c ) + (B t - c )
|
||||
⟍│ x x y y
|
||||
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│╭ 3 2 2 3 ╮2 ╭ 3 2 2 3 ╮2
|
||||
= ││ x (1-t) + 3 x (1-t) t + 2 x (1-t) t + x t - c │ + │ y (1-t) + 3 y (1-t) t + 2 y (1-t) t + y t - c │
|
||||
⟍│╰ 1 2 3 4 x ╯ ╰ 1 2 3 4 y ╯
|
10031
docs/index.html
10299
docs/ja-JP/index.html
@@ -1,181 +1,153 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-GB">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>A Primer on Bézier Curves - Rewriting the tech stack</title>
|
||||
|
||||
<base href=".." />
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>A Primer on Bézier Curves - Rewriting the tech stack</title>
|
||||
|
||||
<link rel="icon" href="images/favicon.png" type="image/png" />
|
||||
<base href="..">
|
||||
|
||||
<link rel="alternate" type="application/rss+xml" title="RSS" href="news/rss.xml" />
|
||||
<link rel="icon" href="images/favicon.png" type="image/png" />
|
||||
|
||||
<!-- page styling -->
|
||||
<link rel="preload" href="images/paper.png" as="image" />
|
||||
<style>
|
||||
:root[lang="en-GB"] {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 18px;
|
||||
}
|
||||
</style>
|
||||
<link rel="alternate" type="application/rss+xml" title="RSS" href="news/rss.xml">
|
||||
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
|
||||
<!-- And a slew of SEO related meta elements, because being discoverable is important -->
|
||||
<meta name="description" content="Rewriting the tech stack" />
|
||||
<!-- page styling -->
|
||||
<link rel="preload" href="images/paper.png" as="image" />
|
||||
<style>
|
||||
|
||||
<!-- opengraph information -->
|
||||
<meta property="og:title" content="Rewriting the tech stack" />
|
||||
<meta property="og:image" content="https://pomax.github.io/bezierinfo/images/og-image.png" />
|
||||
<meta property="og:type" content="text" />
|
||||
<meta property="og:url" content="https://pomax.github.io/bezierinfo/news/2020-09-18.html" />
|
||||
<meta property="og:description" content="Rewriting the tech stack" />
|
||||
<meta property="og:locale" content="en-GB" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:published_time" content="Thu Sep 17 2020 17:00:00 +00:00" />
|
||||
<meta property="og:updated_time" content="Fri Nov 06 2020 11:31:57 +00:00" />
|
||||
<meta property="og:author" content="Mike 'Pomax' Kamermans" />
|
||||
<meta property="og:section" content="Bézier Curves" />
|
||||
<meta property="og:tag" content="Bézier Curves" />
|
||||
|
||||
<!-- twitter card information -->
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:site" content="@TheRealPomax" />
|
||||
<meta name="twitter:creator" content="@TheRealPomax" />
|
||||
<meta name="twitter:image" content="https://pomax.github.io/bezierinfo/images/og-image.png" />
|
||||
<meta name="twitter:url" content="https://pomax.github.io/bezierinfo/news/" />
|
||||
<meta name="twitter:description" content="Rewriting the tech stack" />
|
||||
:root[lang="en-GB"] {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
<!-- my own referral/page hit tracker, because Google knows enough -->
|
||||
<script src="./js/site/referrer.js" type="module" async></script>
|
||||
|
||||
<!--
|
||||
</style>
|
||||
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
|
||||
<!-- And a slew of SEO related meta elements, because being discoverable is important -->
|
||||
<meta name="description" content="Rewriting the tech stack" />
|
||||
|
||||
<!-- opengraph information -->
|
||||
<meta property="og:title" content="Rewriting the tech stack" />
|
||||
<meta property="og:image" content="https://pomax.github.io/bezierinfo/images/og-image.png" />
|
||||
<meta property="og:type" content="text" />
|
||||
<meta property="og:url" content="https://pomax.github.io/bezierinfo/news/2020-09-18.html" />
|
||||
<meta property="og:description" content="Rewriting the tech stack" />
|
||||
<meta property="og:locale" content="en-GB" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:published_time" content="Thu Sep 17 2020 17:00:00 +00:00" />
|
||||
<meta property="og:updated_time" content="Fri Nov 20 2020 17:16:23 +00:00" />
|
||||
<meta property="og:author" content="Mike 'Pomax' Kamermans" />
|
||||
<meta property="og:section" content="Bézier Curves" />
|
||||
<meta property="og:tag" content="Bézier Curves" />
|
||||
|
||||
<!-- twitter card information -->
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:site" content="@TheRealPomax" />
|
||||
<meta name="twitter:creator" content="@TheRealPomax" />
|
||||
<meta name="twitter:image" content="https://pomax.github.io/bezierinfo/images/og-image.png" />
|
||||
<meta name="twitter:url" content="https://pomax.github.io/bezierinfo/news/" />
|
||||
<meta name="twitter:description" content="Rewriting the tech stack" />
|
||||
|
||||
|
||||
|
||||
<!-- my own referral/page hit tracker, because Google knows enough -->
|
||||
<script src="./js/site/referrer.js" type="module" async></script>
|
||||
|
||||
<!--
|
||||
The part that makes interactive graphics work: an HTML5 <graphics-element> custom element.
|
||||
Note that we're not defering this: we just want it to kick in as soon as possible, and
|
||||
given how much HTML there is, that means this can, and thus should, kick in before the
|
||||
document is done even transferring.
|
||||
-->
|
||||
<script src="./js/graphics-element/graphics-element.js" type="module" async></script>
|
||||
<link rel="stylesheet" href="./js/graphics-element/graphics-element.css" />
|
||||
<script src="./js/graphics-element/graphics-element.js" type="module" async></script>
|
||||
<link rel="stylesheet" href="./js/graphics-element/graphics-element.css" />
|
||||
|
||||
<!-- make images lazy load much earlier -->
|
||||
<script src="./js/site/better-lazy-loading.js" type="module" async defer></script>
|
||||
</head>
|
||||
<!-- make images lazy load much earlier -->
|
||||
<script src="./js/site/better-lazy-loading.js" type="module" async defer></script>
|
||||
|
||||
<body>
|
||||
<div class="dev" style="display: none;">
|
||||
DEV PREVIEW ONLY
|
||||
<script>
|
||||
(function () {
|
||||
var loc = window.location.toString();
|
||||
if (loc.includes("localhost") || loc.includes("BezierInfo-2")) {
|
||||
var e = document.querySelector("div.dev");
|
||||
e.removeAttribute("style");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
</head>
|
||||
|
||||
<div class="github">
|
||||
<img src="images/ribbon.png" alt="This page on GitHub" style="border: none;" usemap="#githubmap" width="200" height="149" />
|
||||
<map name="githubmap">
|
||||
<area shape="poly" coords="30,0, 200,0, 200,114" href="http://github.com/pomax/BezierInfo-2" alt="This page on GitHub" />
|
||||
</map>
|
||||
</div>
|
||||
<body>
|
||||
<div class="dev" style="display:none;">
|
||||
DEV PREVIEW ONLY
|
||||
<script>
|
||||
(function () {
|
||||
var loc = window.location.toString();
|
||||
if (loc.includes('localhost') || loc.includes('BezierInfo-2')) {
|
||||
var e = document.querySelector('div.dev');
|
||||
e.removeAttribute("style");
|
||||
}
|
||||
}());
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<header>
|
||||
<h1>Rewriting the tech stack</h1>
|
||||
<h5 class="post-date">Fri, 18 Sep 2020</h5>
|
||||
</header>
|
||||
<div class="github">
|
||||
<img src="images/ribbon.png" alt="This page on GitHub" style="border:none;" useMap="#githubmap" width="200" height="149" />
|
||||
<map name="githubmap">
|
||||
<area shape="poly" coords="30,0, 200,0, 200,114" href="http://github.com/pomax/BezierInfo-2" alt="This page on GitHub" />
|
||||
</map>
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<!-- Because people probably want to share this article -->
|
||||
<div class="notforprint scl">
|
||||
<img src="images/icons.gif" usemap="#rhtimap" title="Share this on social media" />
|
||||
<map name="rhtimap">
|
||||
<area
|
||||
class="sclnk-rdt"
|
||||
shape="rect"
|
||||
coords="0, 0, 19, 15"
|
||||
href="https://www.reddit.com/submit?url=https://pomax.github.io/bezierinfo/news/2020-09-18.html&title==A Primer on Bézier Curves - Rewriting the tech stack&text=An update about the Primer on Bézier curves."
|
||||
alt="submit to reddit"
|
||||
title="submit to reddit"
|
||||
/>
|
||||
<area
|
||||
class="sclnk-hn"
|
||||
shape="rect"
|
||||
coords="0, 20, 19, 35"
|
||||
href="https://news.ycombinator.com/submitlink?u=https://pomax.github.io/bezierinfo/news/2020-09-18.html&t=A Primer on Bézier Curves - Rewriting the tech stack"
|
||||
alt="submit to hacker news"
|
||||
title="submit to hacker news"
|
||||
/>
|
||||
<area
|
||||
class="sclnk-twt"
|
||||
shape="rect"
|
||||
coords="0, 40, 19, 55"
|
||||
href="https://twitter.com/intent/tweet?hashtags=bezier,curves,maths&original_referer=https://pomax.github.io/bezierinfo&text=Reading “Rewriting the tech stack” by @TheRealPomax over on https://pomax.github.io/bezierinfo/news/2020-09-18.html"
|
||||
alt="tweet your read"
|
||||
title="tweet your read"
|
||||
/>
|
||||
</map>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Once upon a time, I needed to draw some Bezier curves because I was trying to create a Japanese kanji composition system that turned strokes
|
||||
into outlines, and that required knowing how to offset Bezier curves and... at the time (2011, time flies) there was no good single source of
|
||||
information for Bezier curves on the web. So I made one. Sure it started small, but it turns out that if you just keep adding bits to
|
||||
something, several years later you have quite the monster, and a single HTML file becomes intractible.
|
||||
</p>
|
||||
<p>
|
||||
So, in 2016, when <a href="https://reactjs.org/">React.js</a> exploded onto the scene, I rewrote the primer as a React app, and it became a
|
||||
lot easier to maintain. Like, <em>a lot</em> a lot. However, there was a downside: no JS meant no content. Sure, server-side rendering sort of
|
||||
existed, but not really, and because the Primer is hosted through github, there was no "server" to run. Plus, trying to rehydrate an app the
|
||||
size of the Primer from a giant HTML file had truly <em>dire</em> performance.
|
||||
</p>
|
||||
<p>
|
||||
So I left it a regular React app, and every time I thought "wouldn't it be nice if it was just... a web page again?" the browser landscape
|
||||
just hadn't caught up. Finally, in 2020, things are different: with a global pandemic, and some vacation time, and something random causing me
|
||||
to look up the state of HTML custom elements, everything was pointing at it being time to finally, <em>finally</em>, turn the Primer back into
|
||||
a normal web page.
|
||||
</p>
|
||||
<p>
|
||||
The new tech stack is, frankly, pretty amazing. It does some things that weren't possible even half a year before I started the rewrite, let
|
||||
alone being possible in 2016, and so because so much has changed, this post will be the first in a series of posts on how the new tech stack
|
||||
works.
|
||||
</p>
|
||||
<p>To give a bit of a teaser, some of the things I'll be writing about:</p>
|
||||
<ul>
|
||||
<li>Essentially reinventing (a limited form of) Processing.js</li>
|
||||
<li>Writing a custom build system, because I'm exhausted with Webpack and hope to never use it again.</li>
|
||||
<li>Using modern ES module code that runs in both the browser and Node.js.</li>
|
||||
<li>
|
||||
Chapter content written as easy to read and write markdown format: <a href="./news/2020-09-18.md">view this blog post's source file</a>.
|
||||
</li>
|
||||
<li>A custom <code><graphics-element></code> element that turns a <code>src="blah.js"</code> into an interactive canvas graphic...</li>
|
||||
<li>
|
||||
...with that same source code being read in and run by Node.js <em>on a canvas</em> to generate fallback images so that even without JS,
|
||||
graphics work.
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<graphics-element title="An example graphic" width="275" height="275" src="./news/example.js">
|
||||
<fallback-image>
|
||||
<span class="view-source">Scripts are disabled. Showing fallback image.</span>
|
||||
<img width="275px" height="275px" src="./images/news/2020-09-18.html/b465a1526a406578c9806a9985e2dbd0.png" loading="lazy" />
|
||||
<label>An example graphic</label>
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
</blockquote>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Real LaTeX code, that gets saved as <code>.tex</code> file, so it can be compiled into optimized SVG using <code>xelatex</code>,
|
||||
<code>pdfcrop</code>, <code>pdf2svg</code>, and <code>svgo</code>:
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<!--
|
||||
<header>
|
||||
|
||||
<h1>Rewriting the tech stack</h1>
|
||||
<h5 class="post-date">Fri, 18 Sep 2020</h5>
|
||||
|
||||
</header>
|
||||
|
||||
<main>
|
||||
|
||||
<!-- Because people probably want to share this article -->
|
||||
<div class="notforprint scl">
|
||||
<img src="images/icons.gif" usemap="#rhtimap" title="Share this on social media" />
|
||||
<map name="rhtimap">
|
||||
<area class="sclnk-rdt" shape="rect" coords="0, 0, 19, 15"
|
||||
href="https://www.reddit.com/submit?url=https://pomax.github.io/bezierinfo/news/2020-09-18.html&title==A Primer on Bézier Curves - Rewriting the tech stack&text=An update about the Primer on Bézier curves."
|
||||
alt="submit to reddit" title="submit to reddit">
|
||||
<area class="sclnk-hn" shape="rect" coords="0, 20, 19, 35"
|
||||
href="https://news.ycombinator.com/submitlink?u=https://pomax.github.io/bezierinfo/news/2020-09-18.html&t=A Primer on Bézier Curves - Rewriting the tech stack"
|
||||
alt="submit to hacker news" title="submit to hacker news">
|
||||
<area class="sclnk-twt" shape="rect" coords="0, 40, 19, 55"
|
||||
href="https://twitter.com/intent/tweet?hashtags=bezier,curves,maths&original_referer=https://pomax.github.io/bezierinfo&text=Reading “Rewriting the tech stack” by @TheRealPomax over on https://pomax.github.io/bezierinfo/news/2020-09-18.html"
|
||||
alt="tweet your read" title="tweet your read">
|
||||
</map>
|
||||
</div>
|
||||
|
||||
|
||||
<p>Once upon a time, I needed to draw some Bezier curves because I was trying to create a Japanese kanji composition system that turned strokes into outlines, and that required knowing how to offset Bezier curves and... at the time (2011, time flies) there was no good single source of information for Bezier curves on the web. So I made one. Sure it started small, but it turns out that if you just keep adding bits to something, several years later you have quite the monster, and a single HTML file becomes intractible.</p>
|
||||
<p>So, in 2016, when <a href="https://reactjs.org/">React.js</a> exploded onto the scene, I rewrote the primer as a React app, and it became a lot easier to maintain. Like, <em>a lot</em> a lot. However, there was a downside: no JS meant no content. Sure, server-side rendering sort of existed, but not really, and because the Primer is hosted through github, there was no "server" to run. Plus, trying to rehydrate an app the size of the Primer from a giant HTML file had truly <em>dire</em> performance.</p>
|
||||
<p>So I left it a regular React app, and every time I thought "wouldn't it be nice if it was just... a web page again?" the browser landscape just hadn't caught up. Finally, in 2020, things are different: with a global pandemic, and some vacation time, and something random causing me to look up the state of HTML custom elements, everything was pointing at it being time to finally, <em>finally</em>, turn the Primer back into a normal web page.</p>
|
||||
<p>The new tech stack is, frankly, pretty amazing. It does some things that weren't possible even half a year before I started the rewrite, let alone being possible in 2016, and so because so much has changed, this post will be the first in a series of posts on how the new tech stack works.</p>
|
||||
<p>To give a bit of a teaser, some of the things I'll be writing about:</p>
|
||||
<ul>
|
||||
<li>Essentially reinventing (a limited form of) Processing.js</li>
|
||||
<li>Writing a custom build system, because I'm exhausted with Webpack and hope to never use it again.</li>
|
||||
<li>Using modern ES module code that runs in both the browser and Node.js.</li>
|
||||
<li>Chapter content written as easy to read and write markdown format: <a href="./news/2020-09-18.md">view this blog post's source file</a>.</li>
|
||||
<li>A custom <code><graphics-element></code> element that turns a <code>src="blah.js"</code> into an interactive canvas graphic...</li>
|
||||
<li>...with that same source code being read in and run by Node.js <em>on a canvas</em> to generate fallback images so that even without JS, graphics work.</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<graphics-element title="An example graphic" width="275" height="275" src="./news/example.js" >
|
||||
<fallback-image>
|
||||
<span class="view-source">Scripts are disabled. Showing fallback image.</span>
|
||||
<img width="275px" height="275px" src="./images/news/2020-09-18.html/b465a1526a406578c9806a9985e2dbd0.png" loading="lazy">
|
||||
<label>An example graphic</label>
|
||||
</fallback-image></graphics-element>
|
||||
</blockquote>
|
||||
|
||||
<ul>
|
||||
<li>Real LaTeX code, that gets saved as <code>.tex</code> file, so it can be compiled into optimized SVG using <code>xelatex</code>, <code>pdfcrop</code>, <code>pdf2svg</code>, and <code>svgo</code>:</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<!--
|
||||
\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math
|
||||
|
||||
__ n=3 n-k k
|
||||
@@ -188,22 +160,18 @@
|
||||
|
||||
0 1 2 3
|
||||
-->
|
||||
<img class="LaTeX SVG" src="./images/news/2020-09-18.html/15225da473048d8c7b5b473b89de0b66.svg" width="401px" height="97px" loading="lazy" />
|
||||
</blockquote>
|
||||
<img class="LaTeX SVG" src="./images/news/2020-09-18.html/15225da473048d8c7b5b473b89de0b66.svg" width="401px" height="97px" loading="lazy">
|
||||
</blockquote>
|
||||
|
||||
<ul>
|
||||
<li>"Lazy loaded everything", so that you get what you need, only when or even just before you need it.</li>
|
||||
<li>Localized content based on a simple filenaming scheme.</li>
|
||||
<li>Nicely formatted HTML, CSS, and JS thanks to <code>prettier</code>.</li>
|
||||
<li>with some code formatting so that there are line numbers without needing JS:</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>"Lazy loaded everything", so that you get what you need, only when or even just before you need it.</li>
|
||||
<li>Localized content based on a simple filenaming scheme.</li>
|
||||
<li>Nicely formatted HTML, CSS, and JS thanks to <code>prettier</code>.</li>
|
||||
<li>with some code formatting so that there are line numbers without needing JS:</li>
|
||||
</ul>
|
||||
|
||||
<table class="code">
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td rowspan="13">
|
||||
<textarea disabled rows="13" role="doc-example">
|
||||
let curve;
|
||||
<table class="code"><tr><td>1</td><td rowspan="13">
|
||||
<textarea disabled rows="13" role="doc-example">let curve;
|
||||
|
||||
setup() {
|
||||
curve = Bezier.defaultCubic();
|
||||
@@ -215,68 +183,44 @@ draw() {
|
||||
clear(`lightblue`);
|
||||
curve.drawCurve();
|
||||
curve.drawPoints();
|
||||
}</textarea
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>4</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>6</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>7</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>8</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>9</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>11</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>12</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>13</td>
|
||||
</tr>
|
||||
</table>
|
||||
}</textarea>
|
||||
</td></tr>
|
||||
<tr><td>2</td></tr>
|
||||
<tr><td>3</td></tr>
|
||||
<tr><td>4</td></tr>
|
||||
<tr><td>5</td></tr>
|
||||
<tr><td>6</td></tr>
|
||||
<tr><td>7</td></tr>
|
||||
<tr><td>8</td></tr>
|
||||
<tr><td>9</td></tr>
|
||||
<tr><td>10</td></tr>
|
||||
<tr><td>11</td></tr>
|
||||
<tr><td>12</td></tr>
|
||||
<tr><td>13</td></tr></table>
|
||||
|
||||
<ul>
|
||||
<li>Responsive CSS, so the content intelligently reflows where possible.</li>
|
||||
<li>A "Live build" setup for working on the content and code.</li>
|
||||
<li>Automatic link-checking to make sure none of the links in the Primer lead you to a 404.</li>
|
||||
<li>This "news" section, so that I can write posts to go along with new sections getting added, or notable changes being made.</li>
|
||||
</ul>
|
||||
<p>
|
||||
It's going to take me a while to detail the entire tech stack, but ultimately what matters is that you get a Primer that is a normal "vanilla"
|
||||
HTML, CSS, and JS page again, that "just works" even with JS disabled.
|
||||
</p>
|
||||
<p>
|
||||
Enjoy <a href="https://pomax.github.io/bezierinfo">The new Primer on Bézier Curves</a>, and if you find any problems,
|
||||
<a href="https://github.com/Pomax/BezierInfo-2/issues">you know where to go</a>.
|
||||
</p>
|
||||
<p>See you in the next post!</p>
|
||||
<p>— <a href="https://twitter.com/TheRealPomax">Pomax</a></p>
|
||||
</main>
|
||||
<ul>
|
||||
<li>Responsive CSS, so the content intelligently reflows where possible.</li>
|
||||
<li>A "Live build" setup for working on the content and code.</li>
|
||||
<li>Automatic link-checking to make sure none of the links in the Primer lead you to a 404.</li>
|
||||
<li>This "news" section, so that I can write posts to go along with new sections getting added, or notable changes being made.</li>
|
||||
</ul>
|
||||
<p>It's going to take me a while to detail the entire tech stack, but ultimately what matters is that you get a Primer that is a normal "vanilla" HTML, CSS, and JS page again, that "just works" even with JS disabled.</p>
|
||||
<p>Enjoy <a href="https://pomax.github.io/bezierinfo">The new Primer on Bézier Curves</a>, and if you find any problems, <a href="https://github.com/Pomax/BezierInfo-2/issues">you know where to go</a>.</p>
|
||||
<p>See you in the next post!</p>
|
||||
<p>— <a href="https://twitter.com/TheRealPomax">Pomax</a></p>
|
||||
|
||||
<hr />
|
||||
|
||||
<footer class="copyright">This post is a news entry for the <a href="https://pomax.github.io/bezierinfo/">Primer on Bézier Curves</a></footer>
|
||||
</body>
|
||||
</main>
|
||||
|
||||
<hr>
|
||||
|
||||
<footer class="copyright">
|
||||
|
||||
This post is a news entry for the <a href="https://pomax.github.io/bezierinfo/">Primer on Bézier Curves</a>
|
||||
|
||||
</footer>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@@ -1,112 +1,137 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-GB">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>A Primer on Bézier Curves - News</title>
|
||||
|
||||
<base href=".." />
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>A Primer on Bézier Curves - News</title>
|
||||
|
||||
<link rel="icon" href="images/favicon.png" type="image/png" />
|
||||
<base href="..">
|
||||
|
||||
<link rel="alternate" type="application/rss+xml" title="RSS" href="news/rss.xml" />
|
||||
<link rel="icon" href="images/favicon.png" type="image/png" />
|
||||
|
||||
<!-- page styling -->
|
||||
<link rel="preload" href="images/paper.png" as="image" />
|
||||
<style>
|
||||
:root[lang="en-GB"] {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 18px;
|
||||
}
|
||||
</style>
|
||||
<link rel="alternate" type="application/rss+xml" title="RSS" href="news/rss.xml">
|
||||
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
|
||||
<!-- And a slew of SEO related meta elements, because being discoverable is important -->
|
||||
<meta name="description" content="" />
|
||||
<!-- page styling -->
|
||||
<link rel="preload" href="images/paper.png" as="image" />
|
||||
<style>
|
||||
|
||||
<!-- opengraph information -->
|
||||
<meta property="og:title" content="" />
|
||||
<meta property="og:image" content="https://pomax.github.io/bezierinfo/images/og-image.png" />
|
||||
<meta property="og:type" content="text" />
|
||||
<meta property="og:url" content="https://pomax.github.io/bezierinfo" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:locale" content="en-GB" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:published_time" content="Fri Nov 06 2020 11:31:57 GMT-0800 (Pacific Standard Time)" />
|
||||
<meta property="og:updated_time" content="" />
|
||||
<meta property="og:author" content="Mike 'Pomax' Kamermans" />
|
||||
<meta property="og:section" content="Bézier Curves" />
|
||||
<meta property="og:tag" content="Bézier Curves" />
|
||||
|
||||
<!-- twitter card information -->
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:site" content="@TheRealPomax" />
|
||||
<meta name="twitter:creator" content="@TheRealPomax" />
|
||||
<meta name="twitter:image" content="https://pomax.github.io/bezierinfo/images/og-image.png" />
|
||||
<meta name="twitter:url" content="https://pomax.github.io/bezierinfo" />
|
||||
<meta name="twitter:description" content="" />
|
||||
:root[lang="en-GB"] {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
<!-- my own referral/page hit tracker, because Google knows enough -->
|
||||
<script src="./js/site/referrer.js" type="module" async></script>
|
||||
|
||||
<!--
|
||||
</style>
|
||||
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
|
||||
<!-- And a slew of SEO related meta elements, because being discoverable is important -->
|
||||
<meta name="description" content="" />
|
||||
|
||||
<!-- opengraph information -->
|
||||
<meta property="og:title" content="" />
|
||||
<meta property="og:image" content="https://pomax.github.io/bezierinfo/images/og-image.png" />
|
||||
<meta property="og:type" content="text" />
|
||||
<meta property="og:url" content="https://pomax.github.io/bezierinfo" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:locale" content="en-GB" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:published_time" content="Fri Nov 20 2020 17:16:23 GMT-0800 (Pacific Standard Time)" />
|
||||
<meta property="og:updated_time" content="" />
|
||||
<meta property="og:author" content="Mike 'Pomax' Kamermans" />
|
||||
<meta property="og:section" content="Bézier Curves" />
|
||||
<meta property="og:tag" content="Bézier Curves" />
|
||||
|
||||
<!-- twitter card information -->
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:site" content="@TheRealPomax" />
|
||||
<meta name="twitter:creator" content="@TheRealPomax" />
|
||||
<meta name="twitter:image" content="https://pomax.github.io/bezierinfo/images/og-image.png" />
|
||||
<meta name="twitter:url" content="https://pomax.github.io/bezierinfo" />
|
||||
<meta name="twitter:description" content="" />
|
||||
|
||||
|
||||
|
||||
<!-- my own referral/page hit tracker, because Google knows enough -->
|
||||
<script src="./js/site/referrer.js" type="module" async></script>
|
||||
|
||||
<!--
|
||||
The part that makes interactive graphics work: an HTML5 <graphics-element> custom element.
|
||||
Note that we're not defering this: we just want it to kick in as soon as possible, and
|
||||
given how much HTML there is, that means this can, and thus should, kick in before the
|
||||
document is done even transferring.
|
||||
-->
|
||||
<script src="./js/graphics-element/graphics-element.js" type="module" async></script>
|
||||
<link rel="stylesheet" href="./js/graphics-element/graphics-element.css" />
|
||||
<script src="./js/graphics-element/graphics-element.js" type="module" async></script>
|
||||
<link rel="stylesheet" href="./js/graphics-element/graphics-element.css" />
|
||||
|
||||
<!-- make images lazy load much earlier -->
|
||||
<script src="./js/site/better-lazy-loading.js" type="module" async defer></script>
|
||||
</head>
|
||||
<!-- make images lazy load much earlier -->
|
||||
<script src="./js/site/better-lazy-loading.js" type="module" async defer></script>
|
||||
|
||||
<body>
|
||||
<div class="dev" style="display: none;">
|
||||
DEV PREVIEW ONLY
|
||||
<script>
|
||||
(function () {
|
||||
var loc = window.location.toString();
|
||||
if (loc.includes("localhost") || loc.includes("BezierInfo-2")) {
|
||||
var e = document.querySelector("div.dev");
|
||||
e.removeAttribute("style");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
</head>
|
||||
|
||||
<div class="github">
|
||||
<img src="images/ribbon.png" alt="This page on GitHub" style="border: none;" usemap="#githubmap" width="200" height="149" />
|
||||
<map name="githubmap">
|
||||
<area shape="poly" coords="30,0, 200,0, 200,114" href="http://github.com/pomax/BezierInfo-2" alt="This page on GitHub" />
|
||||
</map>
|
||||
</div>
|
||||
<body>
|
||||
<div class="dev" style="display:none;">
|
||||
DEV PREVIEW ONLY
|
||||
<script>
|
||||
(function () {
|
||||
var loc = window.location.toString();
|
||||
if (loc.includes('localhost') || loc.includes('BezierInfo-2')) {
|
||||
var e = document.querySelector('div.dev');
|
||||
e.removeAttribute("style");
|
||||
}
|
||||
}());
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<header>
|
||||
<h1>News posts</h1>
|
||||
</header>
|
||||
<div class="github">
|
||||
<img src="images/ribbon.png" alt="This page on GitHub" style="border:none;" useMap="#githubmap" width="200" height="149" />
|
||||
<map name="githubmap">
|
||||
<area shape="poly" coords="30,0, 200,0, 200,114" href="http://github.com/pomax/BezierInfo-2" alt="This page on GitHub" />
|
||||
</map>
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<p>
|
||||
Every now and then the Primer gets updated - these posts chronicle the evolution of the site, and hopefully offer interesting information not
|
||||
just about the process of maintaining a resource like this, but also neat tech tricks, implementation approaches, maths that didn't make it
|
||||
into the primer itself, etc.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This section is still very new, so for the moment there aren't all that many posts up yet, but there's a series of posts planned already, and
|
||||
if you're the kind of person who likes to keep tabs on updates by using RSS: good news, <a href="news/rss.xml">have an RSS link!</a>.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="news/2020-09-18.html">Rewriting the tech stack</a> (Fri, 18 Sep 2020)</li>
|
||||
</ul>
|
||||
</main>
|
||||
<header>
|
||||
|
||||
<hr />
|
||||
<h1>News posts</h1>
|
||||
|
||||
</header>
|
||||
|
||||
<main>
|
||||
|
||||
<p>
|
||||
Every now and then the Primer gets updated - these posts chronicle the evolution of the site,
|
||||
and hopefully offer interesting information not just about the process of maintaining a resource
|
||||
like this, but also neat tech tricks, implementation approaches, maths that didn't make it into
|
||||
the primer itself, etc.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This section is still very new, so for the moment there aren't all that many posts up yet, but
|
||||
there's a series of posts planned already, and if you're the kind of person who likes to keep
|
||||
tabs on updates by using RSS: good news, <a href="news/rss.xml">have an RSS link!</a>.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="news/2020-09-18.html">Rewriting the tech stack</a> (Fri, 18 Sep 2020) </li>
|
||||
|
||||
</ul>
|
||||
|
||||
</main>
|
||||
|
||||
<hr>
|
||||
|
||||
<footer class="copyright">
|
||||
|
||||
This post is a news entry for the <a href="..">Primer on Bézier Curves</a>
|
||||
|
||||
</footer>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
<footer class="copyright">This post is a news entry for the <a href="..">Primer on Bézier Curves</a></footer>
|
||||
</body>
|
||||
</html>
|
@@ -6,7 +6,7 @@
|
||||
<atom:link href="https://pomax.github.io/bezierinfo" rel="self"></atom:link>
|
||||
<description>News updates for the <a href="https://pomax.github.io/bezierinfo">primer on Bézier Curves</a> by Pomax</description>
|
||||
<language>en-GB</language>
|
||||
<lastBuildDate>Fri Nov 06 2020 11:31:57 +00:00</lastBuildDate>
|
||||
<lastBuildDate>Fri Nov 20 2020 17:16:23 +00:00</lastBuildDate>
|
||||
<image>
|
||||
<url>https://pomax.github.io/bezierinfo/images/og-image.png</url>
|
||||
<title>A Primer on Bézier Curves</title>
|
||||
|