isocube 2026.913.1405
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +63 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +41 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +148 -0
- package/examples/hello-world.svg +1 -0
- package/examples/hello.svg +1 -0
- package/examples/isocube.svg +1 -0
- package/examples/repeat-color.svg +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 yuyakinjo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# isocube
|
|
2
|
+
|
|
3
|
+
Generate colorful block-letter logos as transparent SVGs. No API key, external fonts, or runtime dependencies required. Supports Node.js 22 or later.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
One row, random RGB color for each character. Colors vary on each run; the image below is one example.
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npx isocube --text HELLO --out output/hello.svg
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
Two rows: hello / world.
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npx isocube --text helloworld --break-at 5 \
|
|
21
|
+
--colors '#2D00F7,#E500A4,#F20089,#FFB600,#6A00F4,#8900F2,#BC00DD' \
|
|
22
|
+
--out output/hello-world.svg
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+

|
|
26
|
+
|
|
27
|
+
Three rows: ABC / DEF / GHI.
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
npx isocube --text ABCDEFGHI --break-at 3,6 \
|
|
31
|
+
--colors 'rgb(45,0,247),#E500A4' --out output/repeat-color.svg
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
| Option | Description |
|
|
37
|
+
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
38
|
+
| `--text` | Required. 1–256 ASCII letters, digits, or actual newlines. Lowercase becomes uppercase. No spaces or other characters. |
|
|
39
|
+
| `--break-at` | Optional ascending cumulative character positions, e.g. `4` or `3,6`. Cannot be combined with embedded newlines. |
|
|
40
|
+
| `--colors` | Optional comma-separated `#RGB`, `#RRGGBB`, or `rgb(r,g,b)` colors. A short palette repeats across rows. Defaults to independent random RGB values for each character. |
|
|
41
|
+
| `--out` | SVG output path. Default: `output/logo.svg`. Existing files are overwritten. |
|
|
42
|
+
| `--force` | Accepted for compatibility. Existing files are overwritten by default. |
|
|
43
|
+
| `--help` | Show usage. |
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## JavaScript API
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
import { generateLogo } from 'isocube';
|
|
50
|
+
|
|
51
|
+
const { svg, lines, colors } = generateLogo({
|
|
52
|
+
text: 'SAMPLE',
|
|
53
|
+
breakAt: [4],
|
|
54
|
+
colors: ['#2D00F7', '#E500A4'],
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
TypeScript declarations are included.
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
## License
|
|
62
|
+
|
|
63
|
+
MIT
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
import { parseArgs } from 'node:util';
|
|
5
|
+
import { generateLogo } from './index.js';
|
|
6
|
+
try {
|
|
7
|
+
const { values } = parseArgs({
|
|
8
|
+
args: process.argv.slice(2),
|
|
9
|
+
options: {
|
|
10
|
+
text: { type: 'string' },
|
|
11
|
+
'break-at': { type: 'string' },
|
|
12
|
+
colors: { type: 'string' },
|
|
13
|
+
out: { type: 'string', default: 'output/logo.svg' },
|
|
14
|
+
force: { type: 'boolean', default: false },
|
|
15
|
+
help: { type: 'boolean', short: 'h' },
|
|
16
|
+
},
|
|
17
|
+
strict: true,
|
|
18
|
+
});
|
|
19
|
+
if (values.help) {
|
|
20
|
+
console.log('isocube --text DECOPIN [--break-at 4] [--colors "#2D00F7,#E500A4"] [--out output/logo.svg]\n改行位置: 累積文字数をカンマ区切り。色省略: 文字ごとにランダムRGB。対応: A-Z / 0-9。背景透過SVG。同名の出力ファイルは上書き保存します。');
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
if (values.text === undefined)
|
|
24
|
+
throw new Error('--text を指定してください。');
|
|
25
|
+
const result = generateLogo({
|
|
26
|
+
text: values.text,
|
|
27
|
+
breakAt: values['break-at']?.split(',').map(Number),
|
|
28
|
+
colors: values.colors?.split(/,(?![^()]*\))/),
|
|
29
|
+
});
|
|
30
|
+
const output = resolve(values.out);
|
|
31
|
+
if (!output.toLowerCase().endsWith('.svg'))
|
|
32
|
+
throw new Error('--out は .svg ファイルを指定してください。');
|
|
33
|
+
await mkdir(dirname(output), { recursive: true });
|
|
34
|
+
await writeFile(output, result.svg);
|
|
35
|
+
console.log(`${result.lines.join(' / ')} → ${output}\ncolors: ${result.colors.join(',')}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
40
|
+
process.exitCode = 1;
|
|
41
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface LogoOptions {
|
|
2
|
+
text: string;
|
|
3
|
+
/** 改行を入れる文字数の累積位置。例: [4] → DECO / PIN */
|
|
4
|
+
breakAt?: number[];
|
|
5
|
+
/** #RGB / #RRGGBB / rgb(r,g,b)。足りない場合は先頭から繰り返す。 */
|
|
6
|
+
colors?: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function generateLogo(options: LogoOptions): {
|
|
9
|
+
svg: string;
|
|
10
|
+
lines: string[];
|
|
11
|
+
colors: string[];
|
|
12
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// 100×140 の正面。黒い切れ込みと輪郭で文字を描く。
|
|
2
|
+
const GLYPHS = {
|
|
3
|
+
A: { marks: 'M50 35V65 M50 100V140' },
|
|
4
|
+
B: { marks: 'M50 30V50 M50 90V110 M80 70H100' },
|
|
5
|
+
C: { marks: 'M55 70H100' },
|
|
6
|
+
D: {
|
|
7
|
+
outline: [[0, 0], [82, 0], [100, 25], [100, 115], [82, 140], [0, 140]],
|
|
8
|
+
marks: 'M50 42V98',
|
|
9
|
+
},
|
|
10
|
+
E: { marks: 'M55 45H100 M55 95H100' },
|
|
11
|
+
F: { outline: [[0, 0], [100, 0], [100, 90], [55, 90], [55, 140], [0, 140]], marks: 'M55 45H100' },
|
|
12
|
+
G: { marks: 'M100 45H50V95H75' },
|
|
13
|
+
H: { marks: 'M50 0V45 M50 95V140' },
|
|
14
|
+
I: { width: 70 },
|
|
15
|
+
J: {
|
|
16
|
+
outline: [[55, 0], [100, 0], [100, 115], [75, 140], [25, 140], [0, 115], [0, 85], [40, 85], [40, 100], [55, 100]],
|
|
17
|
+
},
|
|
18
|
+
K: {
|
|
19
|
+
outline: [[0, 0], [100, 0], [65, 70], [100, 140], [0, 140]],
|
|
20
|
+
marks: 'M45 0V35 M45 105V140',
|
|
21
|
+
},
|
|
22
|
+
L: { outline: [[0, 0], [55, 0], [55, 100], [100, 100], [100, 140], [0, 140]] },
|
|
23
|
+
M: {
|
|
24
|
+
width: 120,
|
|
25
|
+
outline: [[15, 0], [45, 0], [60, 85], [75, 0], [105, 0], [120, 140], [0, 140]],
|
|
26
|
+
marks: 'M30 140V97.5 M90 140V97.5',
|
|
27
|
+
},
|
|
28
|
+
N: { marks: 'M48 0L56 42 M40 98L48 140' },
|
|
29
|
+
O: { marks: 'M50 42V98' },
|
|
30
|
+
P: { outline: [[0, 0], [100, 0], [100, 90], [50, 90], [50, 140], [0, 140]], marks: 'M42 42H62' },
|
|
31
|
+
Q: { marks: 'M50 35V80 M65 105L100 140' },
|
|
32
|
+
R: { marks: 'M42 42H62 M50 95L75 140 M80 75H100' },
|
|
33
|
+
S: { marks: 'M40 45H100 M0 95H60' },
|
|
34
|
+
T: { outline: [[0, 0], [100, 0], [100, 40], [70, 40], [70, 140], [30, 140], [30, 40], [0, 40]] },
|
|
35
|
+
U: { marks: 'M50 0V95' },
|
|
36
|
+
V: { outline: [[0, 0], [100, 0], [75, 140], [25, 140]], marks: 'M50 0V42.5' },
|
|
37
|
+
W: {
|
|
38
|
+
width: 120,
|
|
39
|
+
outline: [[0, 0], [120, 0], [105, 140], [75, 140], [60, 55], [45, 140], [15, 140]],
|
|
40
|
+
marks: 'M30 0V42.5 M90 0V42.5',
|
|
41
|
+
},
|
|
42
|
+
X: { outline: [[0, 0], [100, 0], [70, 70], [100, 140], [0, 140], [30, 70]] },
|
|
43
|
+
Y: { outline: [[0, 0], [100, 0], [100, 60], [70, 85], [70, 140], [30, 140], [30, 85], [0, 60]], marks: 'M50 0V45' },
|
|
44
|
+
Z: { marks: 'M0 45H60L40 95H100' },
|
|
45
|
+
'0': { marks: 'M50 35V105 M35 85L65 55' },
|
|
46
|
+
'1': { width: 70, outline: [[0, 25], [30, 0], [70, 0], [70, 140], [20, 140], [20, 45], [0, 45]] },
|
|
47
|
+
'2': { marks: 'M0 45H55V70 M45 95H100' },
|
|
48
|
+
'3': { marks: 'M0 45H55 M0 95H55' },
|
|
49
|
+
'4': { marks: 'M50 0V50 M0 100H50V140' },
|
|
50
|
+
'5': { marks: 'M45 45H100 M0 95H55' },
|
|
51
|
+
'6': { marks: 'M55 40H100 M50 90V110' },
|
|
52
|
+
'7': { outline: [[0, 0], [100, 0], [100, 45], [65, 140], [15, 140], [50, 45], [0, 45]] },
|
|
53
|
+
'8': { marks: 'M50 30V50 M50 90V110' },
|
|
54
|
+
'9': { marks: 'M50 30V50 M0 100H50' },
|
|
55
|
+
};
|
|
56
|
+
function colorValue(color) {
|
|
57
|
+
const value = color.trim();
|
|
58
|
+
if (/^#[\da-f]{6}$/i.test(value))
|
|
59
|
+
return value.toUpperCase();
|
|
60
|
+
if (/^#[\da-f]{3}$/i.test(value)) {
|
|
61
|
+
return `#${Array.from(value.slice(1), (digit) => digit.repeat(2)).join('')}`.toUpperCase();
|
|
62
|
+
}
|
|
63
|
+
const rgb = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i.exec(value);
|
|
64
|
+
if (rgb !== null && rgb.slice(1).every((channel) => Number(channel) <= 255)) {
|
|
65
|
+
return `#${rgb
|
|
66
|
+
.slice(1)
|
|
67
|
+
.map((channel) => Number(channel).toString(16).padStart(2, '0'))
|
|
68
|
+
.join('')}`.toUpperCase();
|
|
69
|
+
}
|
|
70
|
+
throw new Error(`Invalid color: ${color}. Use #RGB, #RRGGBB, or rgb(0,0,0).`);
|
|
71
|
+
}
|
|
72
|
+
function randomColor() {
|
|
73
|
+
return `#${[...crypto.getRandomValues(new Uint8Array(3))].map((channel) => channel.toString(16).padStart(2, '0')).join('')}`.toUpperCase();
|
|
74
|
+
}
|
|
75
|
+
export function generateLogo(options) {
|
|
76
|
+
// Unicode の大文字展開 (ß → SS など) を暗黙に受け入れない。
|
|
77
|
+
if (!/^[a-z0-9\n]+$/i.test(options.text) || options.text.length > 256) {
|
|
78
|
+
throw new Error('Enter 1–256 ASCII letters, digits, or line breaks.');
|
|
79
|
+
}
|
|
80
|
+
const text = options.text.toUpperCase();
|
|
81
|
+
const breaks = options.breakAt ?? [];
|
|
82
|
+
if (text.includes('\n') && breaks.length > 0) {
|
|
83
|
+
throw new Error('Line breaks in the text cannot be combined with --break-at.');
|
|
84
|
+
}
|
|
85
|
+
let previous = 0;
|
|
86
|
+
for (const position of breaks) {
|
|
87
|
+
if (!Number.isSafeInteger(position) ||
|
|
88
|
+
position <= previous ||
|
|
89
|
+
position >= text.length) {
|
|
90
|
+
throw new Error('Line break positions must be positive integers in ascending order, each less than the text length.');
|
|
91
|
+
}
|
|
92
|
+
previous = position;
|
|
93
|
+
}
|
|
94
|
+
const lines = breaks.length === 0
|
|
95
|
+
? text.split('\n')
|
|
96
|
+
: [...breaks, text.length].map((end, index) => text.slice(breaks[index - 1] ?? 0, end));
|
|
97
|
+
if (lines.some((line) => line.length === 0))
|
|
98
|
+
throw new Error('Empty lines are not allowed.');
|
|
99
|
+
const palette = options.colors?.map(colorValue);
|
|
100
|
+
if (palette?.length === 0)
|
|
101
|
+
throw new Error('Specify at least one color.');
|
|
102
|
+
const count = lines.join('').length;
|
|
103
|
+
const colors = Array.from({ length: count }, (_, index) => palette === undefined ? randomColor() : palette[index % palette.length]);
|
|
104
|
+
const glyph = (letter) => GLYPHS[letter];
|
|
105
|
+
const widths = lines.map((line) => [...line].reduce((sum, letter) => sum + (glyph(letter).width ?? 100), 0));
|
|
106
|
+
const margin = 12, depth = 40, height = 140, stroke = 5;
|
|
107
|
+
const width = Math.max(...widths) + depth + margin * 2;
|
|
108
|
+
const totalHeight = lines.length * height + depth + margin * 2;
|
|
109
|
+
const faces = [];
|
|
110
|
+
const sides = [];
|
|
111
|
+
let colorIndex = 0;
|
|
112
|
+
for (const [row, line] of lines.entries()) {
|
|
113
|
+
const rowSides = [];
|
|
114
|
+
let x = margin;
|
|
115
|
+
const y = margin + depth + row * height;
|
|
116
|
+
for (const [column, letter] of [...line].entries()) {
|
|
117
|
+
const spec = glyph(letter);
|
|
118
|
+
const w = spec.width ?? 100;
|
|
119
|
+
const color = colors[colorIndex++];
|
|
120
|
+
// 正面と押し出しに同じ輪郭を使い、切り欠きの内側にも面を付ける。
|
|
121
|
+
// D の斜めの右端に次のブロックをかみ合わせる。
|
|
122
|
+
const outline = spec.outline ?? (line[column - 1] === 'D'
|
|
123
|
+
? [[-18, 0], [w, 0], [w, height], [-18, height], [0, 115], [0, 25]]
|
|
124
|
+
: [[0, 0], [w, 0], [w, height], [0, height]]);
|
|
125
|
+
const glyphSides = [];
|
|
126
|
+
for (const [index, start] of outline.entries()) {
|
|
127
|
+
const end = outline[(index + 1) % outline.length];
|
|
128
|
+
const dx = end[0] - start[0];
|
|
129
|
+
const dy = end[1] - start[1];
|
|
130
|
+
if (dx + dy <= 0)
|
|
131
|
+
continue;
|
|
132
|
+
const ax = x + start[0], ay = y + start[1];
|
|
133
|
+
const bx = x + end[0], by = y + end[1];
|
|
134
|
+
glyphSides.push(`<path fill="${color}" d="M${ax} ${ay}L${ax + depth} ${ay - depth}L${bx + depth} ${by - depth}L${bx} ${by}Z"/>`);
|
|
135
|
+
}
|
|
136
|
+
// 下の行から、行内では左から描き、手前の面で隠れる部分を覆う。
|
|
137
|
+
// 行幅や列位置で省略しないことで、隣の切り欠きから見える面も残す。
|
|
138
|
+
rowSides.push(...glyphSides);
|
|
139
|
+
const face = `M${outline.map(([px, py]) => `${px} ${py}`).join('L')}Z`;
|
|
140
|
+
faces.push(`<g transform="translate(${x} ${y})" data-letter="${letter}"><path fill="${color}" d="${face}"/>${spec.marks === undefined ? '' : `<path fill="none" stroke-width="6" d="${spec.marks}"/>`}</g>`);
|
|
141
|
+
x += w;
|
|
142
|
+
}
|
|
143
|
+
sides.unshift(...rowSides);
|
|
144
|
+
}
|
|
145
|
+
const label = lines.join(' / ');
|
|
146
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${totalHeight}" viewBox="0 0 ${width} ${totalHeight}" role="img" aria-labelledby="title"><title id="title">${label}</title><g stroke="#000000" stroke-width="${stroke}" stroke-linejoin="round" stroke-linecap="round">${sides.join('')}${faces.join('')}</g></svg>\n`;
|
|
147
|
+
return { svg, lines, colors };
|
|
148
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="584" height="344" viewBox="0 0 584 344" role="img" aria-labelledby="title"><title id="title">HELLO / WORLD</title><g stroke="#000000" stroke-width="5" stroke-linejoin="round" stroke-linecap="round"><path fill="#8900F2" d="M12 192L52 152L172 152L132 192Z"/><path fill="#8900F2" d="M132 192L172 152L157 292L117 332Z"/><path fill="#8900F2" d="M72 247L112 207L97 292L57 332Z"/><path fill="#BC00DD" d="M132 192L172 152L272 152L232 192Z"/><path fill="#BC00DD" d="M232 192L272 152L272 292L232 332Z"/><path fill="#2D00F7" d="M232 192L272 152L372 152L332 192Z"/><path fill="#2D00F7" d="M332 192L372 152L372 292L332 332Z"/><path fill="#E500A4" d="M332 192L372 152L427 152L387 192Z"/><path fill="#E500A4" d="M387 192L427 152L427 252L387 292Z"/><path fill="#E500A4" d="M387 292L427 252L472 252L432 292Z"/><path fill="#E500A4" d="M432 292L472 252L472 292L432 332Z"/><path fill="#F20089" d="M432 192L472 152L554 152L514 192Z"/><path fill="#F20089" d="M514 192L554 152L572 177L532 217Z"/><path fill="#F20089" d="M532 217L572 177L572 267L532 307Z"/><path fill="#F20089" d="M532 307L572 267L554 292L514 332Z"/><path fill="#2D00F7" d="M12 52L52 12L152 12L112 52Z"/><path fill="#2D00F7" d="M112 52L152 12L152 152L112 192Z"/><path fill="#E500A4" d="M112 52L152 12L252 12L212 52Z"/><path fill="#E500A4" d="M212 52L252 12L252 152L212 192Z"/><path fill="#F20089" d="M212 52L252 12L307 12L267 52Z"/><path fill="#F20089" d="M267 52L307 12L307 112L267 152Z"/><path fill="#F20089" d="M267 152L307 112L352 112L312 152Z"/><path fill="#F20089" d="M312 152L352 112L352 152L312 192Z"/><path fill="#FFB600" d="M312 52L352 12L407 12L367 52Z"/><path fill="#FFB600" d="M367 52L407 12L407 112L367 152Z"/><path fill="#FFB600" d="M367 152L407 112L452 112L412 152Z"/><path fill="#FFB600" d="M412 152L452 112L452 152L412 192Z"/><path fill="#6A00F4" d="M412 52L452 12L552 12L512 52Z"/><path fill="#6A00F4" d="M512 52L552 12L552 152L512 192Z"/><g transform="translate(12 52)" data-letter="H"><path fill="#2D00F7" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 0V45 M50 95V140"/></g><g transform="translate(112 52)" data-letter="E"><path fill="#E500A4" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M55 45H100 M55 95H100"/></g><g transform="translate(212 52)" data-letter="L"><path fill="#F20089" d="M0 0L55 0L55 100L100 100L100 140L0 140Z"/></g><g transform="translate(312 52)" data-letter="L"><path fill="#FFB600" d="M0 0L55 0L55 100L100 100L100 140L0 140Z"/></g><g transform="translate(412 52)" data-letter="O"><path fill="#6A00F4" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 42V98"/></g><g transform="translate(12 192)" data-letter="W"><path fill="#8900F2" d="M0 0L120 0L105 140L75 140L60 55L45 140L15 140Z"/><path fill="none" stroke-width="6" d="M30 0V42.5 M90 0V42.5"/></g><g transform="translate(132 192)" data-letter="O"><path fill="#BC00DD" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 42V98"/></g><g transform="translate(232 192)" data-letter="R"><path fill="#2D00F7" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M42 42H62 M50 95L75 140 M80 75H100"/></g><g transform="translate(332 192)" data-letter="L"><path fill="#E500A4" d="M0 0L55 0L55 100L100 100L100 140L0 140Z"/></g><g transform="translate(432 192)" data-letter="D"><path fill="#F20089" d="M0 0L82 0L100 25L100 115L82 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 42V98"/></g></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="564" height="204" viewBox="0 0 564 204" role="img" aria-labelledby="title"><title id="title">HELLO</title><g stroke="#000000" stroke-width="5" stroke-linejoin="round" stroke-linecap="round"><path fill="#0D2FAA" d="M12 52L52 12L152 12L112 52Z"/><path fill="#0D2FAA" d="M112 52L152 12L152 152L112 192Z"/><path fill="#F2FB0A" d="M112 52L152 12L252 12L212 52Z"/><path fill="#F2FB0A" d="M212 52L252 12L252 152L212 192Z"/><path fill="#A6CCD5" d="M212 52L252 12L307 12L267 52Z"/><path fill="#A6CCD5" d="M267 52L307 12L307 112L267 152Z"/><path fill="#A6CCD5" d="M267 152L307 112L352 112L312 152Z"/><path fill="#A6CCD5" d="M312 152L352 112L352 152L312 192Z"/><path fill="#CA1523" d="M312 52L352 12L407 12L367 52Z"/><path fill="#CA1523" d="M367 52L407 12L407 112L367 152Z"/><path fill="#CA1523" d="M367 152L407 112L452 112L412 152Z"/><path fill="#CA1523" d="M412 152L452 112L452 152L412 192Z"/><path fill="#3AD6C8" d="M412 52L452 12L552 12L512 52Z"/><path fill="#3AD6C8" d="M512 52L552 12L552 152L512 192Z"/><g transform="translate(12 52)" data-letter="H"><path fill="#0D2FAA" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 0V45 M50 95V140"/></g><g transform="translate(112 52)" data-letter="E"><path fill="#F2FB0A" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M55 45H100 M55 95H100"/></g><g transform="translate(212 52)" data-letter="L"><path fill="#A6CCD5" d="M0 0L55 0L55 100L100 100L100 140L0 140Z"/></g><g transform="translate(312 52)" data-letter="L"><path fill="#CA1523" d="M0 0L55 0L55 100L100 100L100 140L0 140Z"/></g><g transform="translate(412 52)" data-letter="O"><path fill="#3AD6C8" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 42V98"/></g></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="734" height="204" viewBox="0 0 734 204" role="img" aria-labelledby="title"><title id="title">ISOCUBE</title><g stroke="#000000" stroke-width="5" stroke-linejoin="round" stroke-linecap="round"><path fill="#B429F9" d="M12 52L52 12L122 12L82 52Z"/><path fill="#B429F9" d="M82 52L122 12L122 152L82 192Z"/><path fill="#9C43F8" d="M82 52L122 12L222 12L182 52Z"/><path fill="#9C43F8" d="M182 52L222 12L222 152L182 192Z"/><path fill="#855DF7" d="M182 52L222 12L322 12L282 52Z"/><path fill="#855DF7" d="M282 52L322 12L322 152L282 192Z"/><path fill="#6D77F6" d="M282 52L322 12L422 12L382 52Z"/><path fill="#6D77F6" d="M382 52L422 12L422 152L382 192Z"/><path fill="#5591F5" d="M382 52L422 12L522 12L482 52Z"/><path fill="#5591F5" d="M482 52L522 12L522 152L482 192Z"/><path fill="#3EABF4" d="M482 52L522 12L622 12L582 52Z"/><path fill="#3EABF4" d="M582 52L622 12L622 152L582 192Z"/><path fill="#26C5F3" d="M582 52L622 12L722 12L682 52Z"/><path fill="#26C5F3" d="M682 52L722 12L722 152L682 192Z"/><g transform="translate(12 52)" data-letter="I"><path fill="#B429F9" d="M0 0L70 0L70 140L0 140Z"/></g><g transform="translate(82 52)" data-letter="S"><path fill="#9C43F8" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M40 45H100 M0 95H60"/></g><g transform="translate(182 52)" data-letter="O"><path fill="#855DF7" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 42V98"/></g><g transform="translate(282 52)" data-letter="C"><path fill="#6D77F6" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M55 70H100"/></g><g transform="translate(382 52)" data-letter="U"><path fill="#5591F5" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 0V95"/></g><g transform="translate(482 52)" data-letter="B"><path fill="#3EABF4" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 30V50 M50 90V110 M80 70H100"/></g><g transform="translate(582 52)" data-letter="E"><path fill="#26C5F3" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M55 45H100 M55 95H100"/></g></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="364" height="484" viewBox="0 0 364 484" role="img" aria-labelledby="title"><title id="title">ABC / DEF / GHI</title><g stroke="#000000" stroke-width="5" stroke-linejoin="round" stroke-linecap="round"><path fill="#2D00F7" d="M12 332L52 292L152 292L112 332Z"/><path fill="#2D00F7" d="M112 332L152 292L152 432L112 472Z"/><path fill="#E500A4" d="M112 332L152 292L252 292L212 332Z"/><path fill="#E500A4" d="M212 332L252 292L252 432L212 472Z"/><path fill="#2D00F7" d="M212 332L252 292L322 292L282 332Z"/><path fill="#2D00F7" d="M282 332L322 292L322 432L282 472Z"/><path fill="#E500A4" d="M12 192L52 152L134 152L94 192Z"/><path fill="#E500A4" d="M94 192L134 152L152 177L112 217Z"/><path fill="#E500A4" d="M112 217L152 177L152 267L112 307Z"/><path fill="#E500A4" d="M112 307L152 267L134 292L94 332Z"/><path fill="#2D00F7" d="M94 192L134 152L252 152L212 192Z"/><path fill="#2D00F7" d="M212 192L252 152L252 292L212 332Z"/><path fill="#E500A4" d="M212 192L252 152L352 152L312 192Z"/><path fill="#E500A4" d="M312 192L352 152L352 242L312 282Z"/><path fill="#E500A4" d="M267 282L307 242L307 292L267 332Z"/><path fill="#2D00F7" d="M12 52L52 12L152 12L112 52Z"/><path fill="#2D00F7" d="M112 52L152 12L152 152L112 192Z"/><path fill="#E500A4" d="M112 52L152 12L252 12L212 52Z"/><path fill="#E500A4" d="M212 52L252 12L252 152L212 192Z"/><path fill="#2D00F7" d="M212 52L252 12L352 12L312 52Z"/><path fill="#2D00F7" d="M312 52L352 12L352 152L312 192Z"/><g transform="translate(12 52)" data-letter="A"><path fill="#2D00F7" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 35V65 M50 100V140"/></g><g transform="translate(112 52)" data-letter="B"><path fill="#E500A4" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 30V50 M50 90V110 M80 70H100"/></g><g transform="translate(212 52)" data-letter="C"><path fill="#2D00F7" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M55 70H100"/></g><g transform="translate(12 192)" data-letter="D"><path fill="#E500A4" d="M0 0L82 0L100 25L100 115L82 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 42V98"/></g><g transform="translate(112 192)" data-letter="E"><path fill="#2D00F7" d="M-18 0L100 0L100 140L-18 140L0 115L0 25Z"/><path fill="none" stroke-width="6" d="M55 45H100 M55 95H100"/></g><g transform="translate(212 192)" data-letter="F"><path fill="#E500A4" d="M0 0L100 0L100 90L55 90L55 140L0 140Z"/><path fill="none" stroke-width="6" d="M55 45H100"/></g><g transform="translate(12 332)" data-letter="G"><path fill="#2D00F7" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M100 45H50V95H75"/></g><g transform="translate(112 332)" data-letter="H"><path fill="#E500A4" d="M0 0L100 0L100 140L0 140Z"/><path fill="none" stroke-width="6" d="M50 0V45 M50 95V140"/></g><g transform="translate(212 332)" data-letter="I"><path fill="#2D00F7" d="M0 0L70 0L70 140L0 140Z"/></g></g></svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "isocube",
|
|
3
|
+
"version": "2026.913.1405",
|
|
4
|
+
"author": "yuyakinjo",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/yuyakinjo/isocube.git"
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"@types/node": "^22.20.2",
|
|
11
|
+
"typescript": "^7.0.2"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"typecheck": "tsc --noEmit && tsc -p web/tsconfig.json",
|
|
16
|
+
"test": "bun run build && bun test",
|
|
17
|
+
"ci": "bun run build && bun test && bun run typecheck && bun run build:site",
|
|
18
|
+
"prepack": "bun run build",
|
|
19
|
+
"version:next": "bun scripts/next-version.ts",
|
|
20
|
+
"build:site": "bun scripts/build-site.ts",
|
|
21
|
+
"dev:site": "bun run build:site && bun scripts/serve-site.ts"
|
|
22
|
+
},
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"bin": {
|
|
30
|
+
"isocube": "dist/cli.js"
|
|
31
|
+
},
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/yuyakinjo/isocube/issues"
|
|
34
|
+
},
|
|
35
|
+
"description": "Generate colorful geometric block-letter SVG logos from text.",
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=26"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"examples"
|
|
42
|
+
],
|
|
43
|
+
"homepage": "https://github.com/yuyakinjo/isocube#readme",
|
|
44
|
+
"keywords": [
|
|
45
|
+
"block-letters",
|
|
46
|
+
"cli",
|
|
47
|
+
"logo",
|
|
48
|
+
"svg",
|
|
49
|
+
"typography"
|
|
50
|
+
],
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
},
|
|
55
|
+
"type": "module"
|
|
56
|
+
}
|