script letters & lines

This commit is contained in:
Julie Blanc 2026-01-11 15:42:09 +01:00
parent cd599ef822
commit 5383628937
44 changed files with 798 additions and 2 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,180 @@
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Italic.woff2') format('woff2'),
url('GeistMono-Italic.woff') format('woff');
font-weight: normal;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-ThinItalic.woff2') format('woff2'),
url('GeistMono-ThinItalic.woff') format('woff');
font-weight: 100;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-ExtraLightItalic.woff2') format('woff2'),
url('GeistMono-ExtraLightItalic.woff') format('woff');
font-weight: 200;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-SemiBold.woff2') format('woff2'),
url('GeistMono-SemiBold.woff') format('woff');
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Regular.woff2') format('woff2'),
url('GeistMono-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-SemiBoldItalic.woff2') format('woff2'),
url('GeistMono-SemiBoldItalic.woff') format('woff');
font-weight: 600;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Italic.woff2') format('woff2'),
url('GeistMono-Italic.woff') format('woff');
font-weight: normal;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-BoldItalic.woff2') format('woff2'),
url('GeistMono-BoldItalic.woff') format('woff');
font-weight: bold;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-MediumItalic.woff2') format('woff2'),
url('GeistMono-MediumItalic.woff') format('woff');
font-weight: 500;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-BlackItalic.woff2') format('woff2'),
url('GeistMono-BlackItalic.woff') format('woff');
font-weight: 900;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Thin.woff2') format('woff2'),
url('GeistMono-Thin.woff') format('woff');
font-weight: 100;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Bold.woff2') format('woff2'),
url('GeistMono-Bold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-LightItalic.woff2') format('woff2'),
url('GeistMono-LightItalic.woff') format('woff');
font-weight: 300;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-ExtraBoldItalic.woff2') format('woff2'),
url('GeistMono-ExtraBoldItalic.woff') format('woff');
font-weight: bold;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Black.woff2') format('woff2'),
url('GeistMono-Black.woff') format('woff');
font-weight: 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-ExtraBold.woff2') format('woff2'),
url('GeistMono-ExtraBold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-ExtraLight.woff2') format('woff2'),
url('GeistMono-ExtraLight.woff') format('woff');
font-weight: 200;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Regular.woff2') format('woff2'),
url('GeistMono-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Medium.woff2') format('woff2'),
url('GeistMono-Medium.woff') format('woff');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Light.woff2') format('woff2'),
url('GeistMono-Light.woff') format('woff');
font-weight: 300;
font-style: normal;
font-display: swap;
}

View file

@ -8,7 +8,225 @@ export default class after extends Handler {
}
afterPageLayout(pageElement, page, breakToken) {
lines(pageElement, ".title, .subtitle, p");
letters(pageElement, ".title, .subtitle, p");
// applyFontSizes(pageElement, ".title, .subtitle");
// grossiPara(pageElement, "p");
}
}
function getRandomLineLength() {
return Math.floor(Math.random() * (34 - 20 + 1)) + 20;
}
function letters(content, elements){
console.log("letters");
let selectedElements = content.querySelectorAll(elements);
selectedElements.forEach(function(element) {
console.log("Type:", element.tagName, element);
// Vérifier si des span.line existent déjà
let lineSpans = element.querySelectorAll('.line');
if (lineSpans.length > 0) {
// Si des lignes existent, appliquer les lettres à chaque ligne
lineSpans.forEach(function(lineSpan) {
let text = lineSpan.textContent;
let chars = text.split('');
lineSpan.innerHTML = '';
chars.forEach(function(char) {
let letterSpan = document.createElement('span');
letterSpan.className = 'letter';
letterSpan.textContent = char;
lineSpan.appendChild(letterSpan);
});
});
console.log("Caractères appliqués dans", lineSpans.length, "lignes");
} else {
// Sinon, appliquer directement sur l'élément
let text = element.textContent;
let chars = text.split('');
element.innerHTML = '';
chars.forEach(function(char) {
let letterSpan = document.createElement('span');
letterSpan.className = 'letter';
letterSpan.textContent = char;
element.appendChild(letterSpan);
});
console.log("Caractères traités:", chars.length);
}
});
}
function grossiPara(content, elements){
console.log("grossiPara");
let selectedElements = content.querySelectorAll(elements);
selectedElements.forEach(function(element) {
// Trouver toutes les lignes
let lineSpans = element.querySelectorAll('.line');
if (lineSpans.length > 0) {
// Appliquer les tailles pour chaque ligne
lineSpans.forEach(function(lineSpan) {
let letterSpans = lineSpan.querySelectorAll('.letter');
let length = letterSpans.length;
letterSpans.forEach(function(letterSpan, i) {
// Progression linéaire de 10px à 28px
let ratio = i / (length - 1);
let fontSize = 10 + (28 - 10) * ratio;
letterSpan.style.fontSize = fontSize + 'px';
});
});
console.log("Progression appliquée sur", lineSpans.length, "lignes");
} else {
// Sinon, appliquer directement sur les lettres de l'élément
let letterSpans = element.querySelectorAll('.letter');
let length = letterSpans.length;
letterSpans.forEach(function(letterSpan, i) {
// Progression linéaire de 10px à 28px
let ratio = i / (length - 1);
let fontSize = 10 + (28 - 10) * ratio;
letterSpan.style.fontSize = fontSize + 'px';
});
console.log("Progression appliquée sur", length, "lettres");
}
});
}
function applyFontSizes(content, elements){
console.log("applyFontSizes");
let selectedElements = content.querySelectorAll(elements);
selectedElements.forEach(function(element) {
// Trouver toutes les lignes
let lineSpans = element.querySelectorAll('.line');
if (lineSpans.length > 0) {
// Appliquer les tailles pour chaque ligne
lineSpans.forEach(function(lineSpan) {
// Chaque ligne a son propre maxSize aléatoire
let maxSize = getRandomLineLength();
console.log("Max size pour cette ligne:", maxSize);
let letterSpans = lineSpan.querySelectorAll('.letter');
let length = letterSpans.length;
// Position aléatoire du pic entre 30% et 70% de la ligne
let peakPosition = Math.random() * (0.7 - 0.3) + 0.3;
let peak = length * peakPosition;
console.log("Pic à la position:", Math.round(peak), "sur", length);
letterSpans.forEach(function(letterSpan, i) {
// Calculer la taille en fonction de la distance au pic
let distanceFromPeak = Math.abs(i - peak);
let maxDistance = Math.max(peak, length - peak);
let ratio = 1 - (distanceFromPeak / maxDistance);
let fontSize = 9 + (maxSize - 9) * ratio;
letterSpan.style.fontSize = fontSize + 'px';
});
});
console.log("Tailles appliquées sur", lineSpans.length, "lignes");
} else {
// Sinon, appliquer directement sur les lettres de l'élément
let maxSize = getRandomLineLength();
console.log("Max size pour cet élément:", maxSize);
let letterSpans = element.querySelectorAll('.letter');
let length = letterSpans.length;
// Position aléatoire du pic entre 30% et 70% de la ligne
let peakPosition = Math.random() * (0.7 - 0.3) + 0.3;
let peak = length * peakPosition;
console.log("Pic à la position:", Math.round(peak), "sur", length);
letterSpans.forEach(function(letterSpan, i) {
// Calculer la taille en fonction de la distance au pic
let distanceFromPeak = Math.abs(i - peak);
let maxDistance = Math.max(peak, length - peak);
let ratio = 1 - (distanceFromPeak / maxDistance);
let fontSize = 9 + (maxSize - 9) * ratio;
letterSpan.style.fontSize = fontSize + 'px';
});
console.log("Tailles appliquées sur", length, "lettres");
}
});
}
function lines(content, elements){
console.log("lines");
let selectedElements = content.querySelectorAll(elements);
selectedElements.forEach(function(element) {
console.log("Type:", element.tagName, element);
let text = element.textContent;
// Créer des spans temporaires pour chaque mot afin de mesurer leur position
let words = text.split(/(\s+)/); // Garde les espaces
element.innerHTML = '';
let wordElements = [];
words.forEach(function(word) {
if (word.length > 0) { // Ignorer les chaînes vides
let span = document.createElement('span');
span.textContent = word;
span.style.display = 'inline';
element.appendChild(span);
let rect = span.getBoundingClientRect();
wordElements.push({
element: span,
word: word,
top: Math.round(rect.top)
});
}
});
// Grouper les mots par ligne avec une tolérance de 2px
let lines = [];
let currentLine = [];
let currentTop = null;
wordElements.forEach(function(wordObj) {
if (currentTop === null || Math.abs(wordObj.top - currentTop) <= 2) {
currentLine.push(wordObj.word);
if (currentTop === null) {
currentTop = wordObj.top;
}
} else {
lines.push(currentLine.join(''));
currentLine = [wordObj.word];
currentTop = wordObj.top;
}
});
if (currentLine.length > 0) {
lines.push(currentLine.join(''));
}
// Reconstruire l'élément avec des span.line
element.innerHTML = '';
lines.forEach(function(lineText) {
let lineSpan = document.createElement('span');
lineSpan.className = 'line';
lineSpan.style.display = 'block';
lineSpan.textContent = lineText;
element.appendChild(lineSpan);
});
console.log("Lignes détectées:", lines.length);
});
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,180 @@
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Italic.woff2') format('woff2'),
url('GeistMono-Italic.woff') format('woff');
font-weight: normal;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-ThinItalic.woff2') format('woff2'),
url('GeistMono-ThinItalic.woff') format('woff');
font-weight: 100;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-ExtraLightItalic.woff2') format('woff2'),
url('GeistMono-ExtraLightItalic.woff') format('woff');
font-weight: 200;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-SemiBold.woff2') format('woff2'),
url('GeistMono-SemiBold.woff') format('woff');
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Regular.woff2') format('woff2'),
url('GeistMono-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-SemiBoldItalic.woff2') format('woff2'),
url('GeistMono-SemiBoldItalic.woff') format('woff');
font-weight: 600;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Italic.woff2') format('woff2'),
url('GeistMono-Italic.woff') format('woff');
font-weight: normal;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-BoldItalic.woff2') format('woff2'),
url('GeistMono-BoldItalic.woff') format('woff');
font-weight: bold;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-MediumItalic.woff2') format('woff2'),
url('GeistMono-MediumItalic.woff') format('woff');
font-weight: 500;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-BlackItalic.woff2') format('woff2'),
url('GeistMono-BlackItalic.woff') format('woff');
font-weight: 900;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Thin.woff2') format('woff2'),
url('GeistMono-Thin.woff') format('woff');
font-weight: 100;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Bold.woff2') format('woff2'),
url('GeistMono-Bold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-LightItalic.woff2') format('woff2'),
url('GeistMono-LightItalic.woff') format('woff');
font-weight: 300;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-ExtraBoldItalic.woff2') format('woff2'),
url('GeistMono-ExtraBoldItalic.woff') format('woff');
font-weight: bold;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Black.woff2') format('woff2'),
url('GeistMono-Black.woff') format('woff');
font-weight: 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-ExtraBold.woff2') format('woff2'),
url('GeistMono-ExtraBold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-ExtraLight.woff2') format('woff2'),
url('GeistMono-ExtraLight.woff') format('woff');
font-weight: 200;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Regular.woff2') format('woff2'),
url('GeistMono-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Medium.woff2') format('woff2'),
url('GeistMono-Medium.woff') format('woff');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src: url('GeistMono-Light.woff2') format('woff2'),
url('GeistMono-Light.woff') format('woff');
font-weight: 300;
font-style: normal;
font-display: swap;
}

View file

@ -8,7 +8,225 @@ export default class after extends Handler {
}
afterPageLayout(pageElement, page, breakToken) {
lines(pageElement, ".title, .subtitle, p");
letters(pageElement, ".title, .subtitle, p");
// applyFontSizes(pageElement, ".title, .subtitle");
// grossiPara(pageElement, "p");
}
}
function getRandomLineLength() {
return Math.floor(Math.random() * (34 - 20 + 1)) + 20;
}
function letters(content, elements){
console.log("letters");
let selectedElements = content.querySelectorAll(elements);
selectedElements.forEach(function(element) {
console.log("Type:", element.tagName, element);
// Vérifier si des span.line existent déjà
let lineSpans = element.querySelectorAll('.line');
if (lineSpans.length > 0) {
// Si des lignes existent, appliquer les lettres à chaque ligne
lineSpans.forEach(function(lineSpan) {
let text = lineSpan.textContent;
let chars = text.split('');
lineSpan.innerHTML = '';
chars.forEach(function(char) {
let letterSpan = document.createElement('span');
letterSpan.className = 'letter';
letterSpan.textContent = char;
lineSpan.appendChild(letterSpan);
});
});
console.log("Caractères appliqués dans", lineSpans.length, "lignes");
} else {
// Sinon, appliquer directement sur l'élément
let text = element.textContent;
let chars = text.split('');
element.innerHTML = '';
chars.forEach(function(char) {
let letterSpan = document.createElement('span');
letterSpan.className = 'letter';
letterSpan.textContent = char;
element.appendChild(letterSpan);
});
console.log("Caractères traités:", chars.length);
}
});
}
function grossiPara(content, elements){
console.log("grossiPara");
let selectedElements = content.querySelectorAll(elements);
selectedElements.forEach(function(element) {
// Trouver toutes les lignes
let lineSpans = element.querySelectorAll('.line');
if (lineSpans.length > 0) {
// Appliquer les tailles pour chaque ligne
lineSpans.forEach(function(lineSpan) {
let letterSpans = lineSpan.querySelectorAll('.letter');
let length = letterSpans.length;
letterSpans.forEach(function(letterSpan, i) {
// Progression linéaire de 10px à 28px
let ratio = i / (length - 1);
let fontSize = 10 + (28 - 10) * ratio;
letterSpan.style.fontSize = fontSize + 'px';
});
});
console.log("Progression appliquée sur", lineSpans.length, "lignes");
} else {
// Sinon, appliquer directement sur les lettres de l'élément
let letterSpans = element.querySelectorAll('.letter');
let length = letterSpans.length;
letterSpans.forEach(function(letterSpan, i) {
// Progression linéaire de 10px à 28px
let ratio = i / (length - 1);
let fontSize = 10 + (28 - 10) * ratio;
letterSpan.style.fontSize = fontSize + 'px';
});
console.log("Progression appliquée sur", length, "lettres");
}
});
}
function applyFontSizes(content, elements){
console.log("applyFontSizes");
let selectedElements = content.querySelectorAll(elements);
selectedElements.forEach(function(element) {
// Trouver toutes les lignes
let lineSpans = element.querySelectorAll('.line');
if (lineSpans.length > 0) {
// Appliquer les tailles pour chaque ligne
lineSpans.forEach(function(lineSpan) {
// Chaque ligne a son propre maxSize aléatoire
let maxSize = getRandomLineLength();
console.log("Max size pour cette ligne:", maxSize);
let letterSpans = lineSpan.querySelectorAll('.letter');
let length = letterSpans.length;
// Position aléatoire du pic entre 30% et 70% de la ligne
let peakPosition = Math.random() * (0.7 - 0.3) + 0.3;
let peak = length * peakPosition;
console.log("Pic à la position:", Math.round(peak), "sur", length);
letterSpans.forEach(function(letterSpan, i) {
// Calculer la taille en fonction de la distance au pic
let distanceFromPeak = Math.abs(i - peak);
let maxDistance = Math.max(peak, length - peak);
let ratio = 1 - (distanceFromPeak / maxDistance);
let fontSize = 9 + (maxSize - 9) * ratio;
letterSpan.style.fontSize = fontSize + 'px';
});
});
console.log("Tailles appliquées sur", lineSpans.length, "lignes");
} else {
// Sinon, appliquer directement sur les lettres de l'élément
let maxSize = getRandomLineLength();
console.log("Max size pour cet élément:", maxSize);
let letterSpans = element.querySelectorAll('.letter');
let length = letterSpans.length;
// Position aléatoire du pic entre 30% et 70% de la ligne
let peakPosition = Math.random() * (0.7 - 0.3) + 0.3;
let peak = length * peakPosition;
console.log("Pic à la position:", Math.round(peak), "sur", length);
letterSpans.forEach(function(letterSpan, i) {
// Calculer la taille en fonction de la distance au pic
let distanceFromPeak = Math.abs(i - peak);
let maxDistance = Math.max(peak, length - peak);
let ratio = 1 - (distanceFromPeak / maxDistance);
let fontSize = 9 + (maxSize - 9) * ratio;
letterSpan.style.fontSize = fontSize + 'px';
});
console.log("Tailles appliquées sur", length, "lettres");
}
});
}
function lines(content, elements){
console.log("lines");
let selectedElements = content.querySelectorAll(elements);
selectedElements.forEach(function(element) {
console.log("Type:", element.tagName, element);
let text = element.textContent;
// Créer des spans temporaires pour chaque mot afin de mesurer leur position
let words = text.split(/(\s+)/); // Garde les espaces
element.innerHTML = '';
let wordElements = [];
words.forEach(function(word) {
if (word.length > 0) { // Ignorer les chaînes vides
let span = document.createElement('span');
span.textContent = word;
span.style.display = 'inline';
element.appendChild(span);
let rect = span.getBoundingClientRect();
wordElements.push({
element: span,
word: word,
top: Math.round(rect.top)
});
}
});
// Grouper les mots par ligne avec une tolérance de 2px
let lines = [];
let currentLine = [];
let currentTop = null;
wordElements.forEach(function(wordObj) {
if (currentTop === null || Math.abs(wordObj.top - currentTop) <= 2) {
currentLine.push(wordObj.word);
if (currentTop === null) {
currentTop = wordObj.top;
}
} else {
lines.push(currentLine.join(''));
currentLine = [wordObj.word];
currentTop = wordObj.top;
}
});
if (currentLine.length > 0) {
lines.push(currentLine.join(''));
}
// Reconstruire l'élément avec des span.line
element.innerHTML = '';
lines.forEach(function(lineText) {
let lineSpan = document.createElement('span');
lineSpan.className = 'line';
lineSpan.style.display = 'block';
lineSpan.textContent = lineText;
element.appendChild(lineSpan);
});
console.log("Lignes détectées:", lines.length);
});
}