Математика трансформаций очень простая.
Отрендерить текст на изображение можно используя
https://opentype.js.org/
Вы можете отрендерить каждую букву используя библиотеку, а далее уже отрендеренные буквы использовать на своем сайте без библиотеки.
Либо использовать эту же библиотеку для того, чтобы получить path data для каждой буквы.
Если ваша трансформация сводится к аффинным преобразованиям, то можно рассчитывать координаты не каждой точки изображения буквы, а только точки, которые участвуют в path data. Таким образом трансформируя все точки path data вы получите такую же path data, используя которую вы начертаете шрифты в любом месте на любом изображении. Это может дать очень выгодный прирост к производительности (потенциально до 1000х раз). Кроме того, линии path data "рисуется" с правильным расчетом межпиксельного пространства, и вам не надо будет делать ресамплинг, как при работе с трансформированием изображений.
Но рисовать шрифты по безье - это не всегда можно свести к аффинным преобразованиям.
На верхней иллюстрации у вас используется искажение по оси X: skewX()
Получить координаты каждой точки можно умножив матрицу с исходными точками на матрицу CTM.
https://www.w3.org/TR/SVG11/coords.html#TransformM...
Сама матрица CTM - это произведение матриц всех трансформаций. То есть, чтобы не умножать матрицу точек на матрицы каждой трансформации, сначала вычисляется произведение матриц всех трансформаций, которое называется CTM.
По ссылке выше вы найдёте матрицы с формулами аффинных преобразований в двухмерном пространстве. Матрицы имеют вид (3х3) из которых 6 чисел значимые, 3 числа - статичные (всегда [0, 0, 1]).
Для 3D-преобразований используются матрицы 4х4 из которых 12 чисел значимые, 4 числа - статичные (всегда [0, 0, 0, 1]):
https://drafts.csswg.org/css-transforms-2/#mathema...
Для расчета 3d-трансформаций с учетом перспективы используются матрицы 8х8.
На нижней иллюстрации у вас используются трехмерные искажения.
Про математику 3D искажении с перспективой можно прочитать тут
https://www.cs.cmu.edu/~ph/texfund/texfund.pdf
Там рассматриваются и формулы получения координат на плоскости и ресамплинг (чтобы, например, не было пикселизации шрифтов после трансформации).
Для перемножений матриц можно использовать функцию
const multiply = (a, b) => a.map((_, r) => b[0].map((_, c) => a[r].reduce((s,_,i) => s + a[r][i] * b[i][c], 0)));
Рассчитать координаты безье можно функциями (соответственно, квадратичная и кубическая безьё):
// [p0x, p0x] - are coordinates of origin point
// [p1x, p1y] - are coordinates of single control point
// [p2x, p2y] - are coordinates of destination point
// T - is number of points that needs to draw the curve
const quadratic = ([p0x,p0y], [p1x,p1y], [p2x,p2y], T = 60) => {
const x = t => (1 - t)**2 * p0x + 2 * (1 - t) * t * p1x + t**2 * p2x;
const y = t => (1 - t)**2 * p0y + 2 * (1 - t) * t * p1y + t**2 * p2y;
return Array.from({ length: T+1 }).map((_, t) => [x(t / T), y(t / T)]);
};
// [p0x, p0x] - are coordinates of origin point
// [p1x, p1y] - are coordinates of first control point
// [p2x, p2y] - are coordinates of second control point
// [p3x, p3y] - are coordinates of destination point
// T - is number of points that needs to draw the curve
const cubic = ([p0x, p0y], [p1x, p1y], [p2x, p2y], [p3x, p3y], T = 60) => {
const y = t => (1 - t)**3 * p0y + 3 * (1 - t)**2 * t * p1y + 3 * (1 - t) * t**2 * p2y + t**3 * p3y;
const x = t => (1 - t)**3 * p0x + 3 * (1 - t)**2 * t * p1x + 3 * (1 - t) * t**2 * p2x + t**3 * p3x;
return Array.from({ length: T+1 }).map((_, t) => [x(t / T), y(t / T)]);
};