-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmstr-generator.js
More file actions
157 lines (130 loc) · 4.75 KB
/
mstr-generator.js
File metadata and controls
157 lines (130 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**
* Generates an SVG animation that displays a sequence of words,
* with the letters 'm', 's', 't', 'r' (in that order) highlighted in bold.
*
* @param {string[]} wordList - Array of words to animate (must contain 'm','s','t','r' in order)
* @param {Object} options - Optional configuration parameters
* @param {number} options.width - SVG width (default: 500)
* @param {number} options.height - SVG height (default: 150)
* @param {number} options.fontSize - Font size in pixels (default: 40)
* @param {number} options.duration - Duration per word in seconds (default: 2)
* @param {string} options.fontFamily - Font family (default: "Times New Roman, serif")
* @returns {string} - SVG markup as a string
*/
function generateMstrAnimation(wordList, options = {}) {
// Default options
const config = {
width: options.width || 500,
height: options.height || 150,
fontSize: options.fontSize || 50,
duration: options.duration || 2,
fontFamily: options.fontFamily || "Times New Roman, serif"
};
// Validate words contain 'm', 's', 't', 'r' in that order
const validWords = wordList.filter(word => containsMSTR(word));
// Randomize order of words
shuffle(validWords);
// add 'mstr' as first word
const finaleWordList = ["mstr"].concat(validWords);
// Calculate animation timing
const totalDuration = config.duration * finaleWordList.length;
const singleWordPercentage = 100 / finaleWordList.length;
const fadePercentage = singleWordPercentage * 0.2; // 20% of the word's time for fading
// Generate SVG with styles and animations
let svg = `<svg viewBox="0 0 ${config.width} ${config.height}" xmlns="http://www.w3.org/2000/svg">
<style>
@font-face {
font-family: 'Times New Roman';
font-style: normal;
font-weight: normal;
}
text {
font-family: ${config.fontFamily};
font-size: ${config.fontSize}px;
dominant-baseline: middle;
text-anchor: middle;
}
.bold {
font-weight: bold;
}
.grey {
font-weight: normal;
fill: grey;
}
@keyframes wordAnimation {
0%, ${singleWordPercentage - fadePercentage}% {
opacity: 1;
}
${singleWordPercentage}%, 100% {
opacity: 0;
}
}
${finaleWordList.map((_, i) => `
#word${i+1} {
opacity: 0;
animation: wordAnimation ${totalDuration}s infinite;
animation-delay: ${i * config.duration}s;
}`).join('\n')}
</style>
<g id="animated-text">`;
// Add each word with properly highlighted letters
finaleWordList.forEach((word, index) => {
const lowerWord = word.toLowerCase();
// Find indices of m, s, t, r
let mIndex = lowerWord.indexOf('m');
let sIndex = lowerWord.indexOf('s', mIndex + 1);
let tIndex = lowerWord.indexOf('t', sIndex + 1);
let rIndex = lowerWord.indexOf('r', tIndex + 1);
// Split the word into segments
const segments = [
{ text: word.substring(0, mIndex), bold: false },
{ text: word.charAt(mIndex), bold: true },
{ text: word.substring(mIndex + 1, sIndex), bold: false },
{ text: word.charAt(sIndex), bold: true },
{ text: word.substring(sIndex + 1, tIndex), bold: false },
{ text: word.charAt(tIndex), bold: true },
{ text: word.substring(tIndex + 1, rIndex), bold: false },
{ text: word.charAt(rIndex), bold: true },
{ text: word.substring(rIndex + 1), bold: false }
];
// Filter out empty segments
const filteredSegments = segments.filter(segment => segment.text.length > 0);
// Generate text element with spans
svg += `
<text id="word${index+1}" x="${config.width/2}" y="${config.height/2}">
${filteredSegments.map(segment =>
`<tspan class="${segment.bold ? 'bold' : 'grey'}">${segment.text}</tspan>`
).join('')}
</text>`;
});
// Close SVG
svg += `
</g>
</svg>`;
return svg;
}
// Function to check if a word contains m,s,t,r in order
function containsMSTR(word) {
const lowerWord = word.toLowerCase();
let mIndex = lowerWord.indexOf('m');
if (mIndex === -1) return false;
let sIndex = lowerWord.indexOf('s', mIndex + 1);
if (sIndex === -1) return false;
let tIndex = lowerWord.indexOf('t', sIndex + 1);
if (tIndex === -1) return false;
let rIndex = lowerWord.indexOf('r', tIndex + 1);
if (rIndex === -1) return false;
return true;
}
function shuffle(array) {
let currentIndex = array.length;
// While there remain elements to shuffle...
while (currentIndex != 0) {
// Pick a remaining element...
let randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
}