Scrabble pseudo-typeface
<p class="scrabble">
Offred is a Handmaid in the Republic of Gilead. She may leave the home of the
Commander and his wife once a day to walk to food markets whose signs are now
pictures instead of words because women are no longer allowed to read. She
must lie on her back once a month and pray that the Commander makes her
pregnant, because in an age of declining births, Offred and the other
Handmaids are valued only if their ovaries are viable. Offred can remember the
years before, when she lived and made love with her husband, Luke; when she
played with and protected her daughter; when she had a job, money of her own,
and access to knowledge. But all of that is gone now...
</p> @font-face {
font-family: "Roboto Mono";
src: url("RobotoMono-Regular.ttf");
font-weight: 400;
font-display: swap;
}
* {
box-sizing: border-box;
}
html {
--loading-display: block;
}
body {
background-color: #b30000;
min-height: 100dvh;
margin: 0;
padding-inline: 0.25rem;
display: grid;
place-items: center;
font-family: "Roboto Mono", monospace;
font-size: 2rem;
text-transform: uppercase;
}
p {
margin-block: 1rem;
}
.scrabble {
display: none;
}
.tile {
position: relative;
display: inline-block;
padding: 0.1em 0.3em;
margin: 0.1em;
background: rgb(243, 230, 210);
border: 1px hsl(43, 81%, 94%) solid;
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.5);
border-radius: 0.1em;
text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.5);
}
.tile::after {
content: attr(data-value);
position: absolute;
right: 0.15em;
bottom: 0.5em;
font-size: 0.3em;
}
.word {
margin-inline-end: 1em;
}
/* loading animation */
body::after {
content: "";
display: var(--loading-display);
width: 3rem;
aspect-ratio: 1;
padding: 0.5rem;
border-radius: 50%;
background: white;
--_m: conic-gradient(#0000 10%, #000), linear-gradient(#000 0 0) content-box;
-webkit-mask: var(--_m);
mask: var(--_m);
-webkit-mask-composite: source-out;
mask-composite: subtract;
animation: spin 1s infinite linear;
}
@keyframes spin {
to {
transform: rotate(1turn);
}
} let targetClass = ".scrabble";
const letterValues = [
{ letter: "A", value: 1 },
{ letter: "B", value: 3 },
{ letter: "C", value: 3 },
{ letter: "D", value: 2 },
{ letter: "E", value: 1 },
{ letter: "F", value: 4 },
{ letter: "G", value: 2 },
{ letter: "H", value: 4 },
{ letter: "I", value: 1 },
{ letter: "J", value: 8 },
{ letter: "K", value: 5 },
{ letter: "L", value: 1 },
{ letter: "M", value: 3 },
{ letter: "N", value: 1 },
{ letter: "O", value: 1 },
{ letter: "P", value: 3 },
{ letter: "Q", value: 10 },
{ letter: "R", value: 1 },
{ letter: "S", value: 1 },
{ letter: "T", value: 1 },
{ letter: "U", value: 1 },
{ letter: "V", value: 4 },
{ letter: "W", value: 4 },
{ letter: "X", value: 8 },
{ letter: "Y", value: 4 },
{ letter: "Z", value: 10 },
];
/* Covert each character to a tile. If the tile is a letter, a value is added as a data attribute. */
function makeTiles() {
let characters = document.querySelectorAll(".char");
for (const characterSpan of characters) {
characterSpan.classList.add("tile");
const letter = characterSpan.innerText;
if (isLetter(letter)) {
addValue(characterSpan);
}
}
}
/* Check if the character provided is a letter */
function isLetter(char) {
if (char.length === 1 && char.match(/[a-z]/i)) {
return true;
}
return false;
}
/* Add the scrabble value for the letter in a span as a data attribute */
function addValue(span) {
const character = span.innerText.toUpperCase();
for (const item of letterValues) {
if (item.letter === character) {
span.setAttribute("data-value", item.value);
break;
}
}
}
/* Make all paragraphs visible. Initially all paragraphs are hidden. */
function showParagraphs() {
let paragraphs = document.querySelectorAll(targetClass);
paragraphs.forEach((p) => p.style.setProperty("display", "block"));
}
function hideLoadingSpinner() {
document.documentElement.style.setProperty("--loading-display", "none");
}
function transformText() {
// creates a span for each letter
Splitting({ target: targetClass, by: "chars" });
makeTiles();
showParagraphs();
hideLoadingSpinner();
}
transformText(); Description
I wanted to transform the characters in a paragraph into individual scrabble tiles. It is a pseudo-typeface really! Any paragraph is transformed by adding the “scrabble” class.
I use the Splitting library to split the paragraph into individual <span> elements.