feat: Initial prototype

This commit is contained in:
abdus committed 2026-10-10 12:51:33 +02:00
commit 819f6a61cd
327 files changed
+252446

No files matched your search

+95
View File
@@ -0,0 +1,95 @@
// Original 5×7 bitmap glyphs. All rendering is local; no fonts or API are fetched.
const patterns = {
A: '01110/10001/10001/11111/10001/10001/10001',
B: '11110/10001/10001/11110/10001/10001/11110',
C: '01111/10000/10000/10000/10000/10000/01111',
D: '11110/10001/10001/10001/10001/10001/11110',
E: '11111/10000/10000/11110/10000/10000/11111',
F: '11111/10000/10000/11110/10000/10000/10000',
G: '01111/10000/10000/10111/10001/10001/01111',
H: '10001/10001/10001/11111/10001/10001/10001',
I: '11111/00100/00100/00100/00100/00100/11111',
J: '00111/00010/00010/00010/10010/10010/01100',
K: '10001/10010/10100/11000/10100/10010/10001',
L: '10000/10000/10000/10000/10000/10000/11111',
M: '10001/11011/10101/10101/10001/10001/10001',
N: '10001/11001/10101/10011/10001/10001/10001',
O: '01110/10001/10001/10001/10001/10001/01110',
P: '11110/10001/10001/11110/10000/10000/10000',
Q: '01110/10001/10001/10001/10101/10010/01101',
R: '11110/10001/10001/11110/10100/10010/10001',
S: '01111/10000/10000/01110/00001/00001/11110',
T: '11111/00100/00100/00100/00100/00100/00100',
U: '10001/10001/10001/10001/10001/10001/01110',
V: '10001/10001/10001/10001/10001/01010/00100',
W: '10001/10001/10001/10101/10101/10101/01010',
X: '10001/10001/01010/00100/01010/10001/10001',
Y: '10001/10001/01010/00100/00100/00100/00100',
Z: '11111/00001/00010/00100/01000/10000/11111',
0: '01110/10001/10011/10101/11001/10001/01110',
1: '00100/01100/00100/00100/00100/00100/01110',
2: '01110/10001/00001/00010/00100/01000/11111',
3: '11110/00001/00001/01110/00001/00001/11110',
4: '00010/00110/01010/10010/11111/00010/00010',
5: '11111/10000/10000/11110/00001/00001/11110',
6: '01110/10000/10000/11110/10001/10001/01110',
7: '11111/00001/00010/00100/01000/01000/01000',
8: '01110/10001/10001/01110/10001/10001/01110',
9: '01110/10001/10001/01111/00001/00001/01110',
' ': '000/000/000/000/000/000/000',
'!': '1/1/1/1/1/0/1',
'?': '01110/10001/00001/00010/00100/00000/00100',
'.': '0/0/0/0/0/0/1',
',': '00/00/00/00/00/01/10',
':': '0/1/0/0/1/0/0',
';': '00/01/00/00/01/01/10',
'-': '000/000/000/111/000/000/000',
'_': '00000/00000/00000/00000/00000/00000/11111',
'+': '00000/00100/00100/11111/00100/00100/00000',
'=': '00000/00000/11111/00000/11111/00000/00000',
'/': '00001/00001/00010/00100/01000/10000/10000',
'\\': '10000/10000/01000/00100/00010/00001/00001',
'(': '001/010/100/100/100/010/001',
')': '100/010/001/001/001/010/100',
'[': '111/100/100/100/100/100/111',
']': '111/001/001/001/001/001/111',
'{': '001/010/010/100/010/010/001',
'}': '100/010/010/001/010/010/100',
'<': '0001/0010/0100/1000/0100/0010/0001',
'>': '1000/0100/0010/0001/0010/0100/1000',
"'": '1/1/0/0/0/0/0',
'"': '101/101/000/000/000/000/000',
'`': '10/01/00/00/00/00/00',
'#': '01010/11111/01010/01010/11111/01010/00000',
'$': '00100/01111/10100/01110/00101/11110/00100',
'%': '11001/11010/00010/00100/01000/01011/10011',
'&': '01100/10010/10100/01000/10101/10010/01101',
'*': '00000/10101/01110/11111/01110/10101/00000',
'@': '01110/10001/10111/10101/10111/10000/01111',
'^': '00100/01010/10001/00000/00000/00000/00000',
'|': '1/1/1/1/1/1/1',
'~': '00000/00000/01001/10110/00000/00000/00000',
};
export const styles = ['block', 'banner', 'slant', 'compact'];
export function normalizeText(text) {
return text.replace(/ı/g, 'i').normalize('NFD').replace(/[\u0300-\u036f]/g, '').toUpperCase();
}
export function render(text, style = 'block') {
if (!styles.includes(style)) throw new Error('Unknown lettering style');
if (text.length > 500) throw new Error('Text is too long');
return normalizeText(text).replace(/\r\n?/g, '\n').split('\n').map(line => {
const characters = [...line.replace(/\t/g, ' ')];
const glyphs = characters.map(char => (patterns[char] || patterns['?']).split('/'));
return Array.from({length: 7}, (_, row) => {
const pixels = glyphs.map((glyph, i) => [...glyph[row]].map(pixel => {
if (style === 'banner') return pixel === '1' ? characters[i] : ' ';
if (style === 'compact') return pixel === '1' ? '#' : ' ';
return pixel === '1' ? '##' : ' ';
}).join('')).join(style === 'compact' || style === 'banner' ? ' ' : ' ');
return (style === 'slant' ? ' '.repeat(6 - row) : '') + pixels.trimEnd();
}).join('\n');
}).join('\n\n');
}