@leftium/logo 0.3.0 → 0.4.0
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/dist/LeftiumLogo.svelte +17 -14
- package/dist/LeftiumLogo.svelte.d.ts +1 -0
- package/dist/app-logo/generate-favicon-set.d.ts +2 -2
- package/dist/app-logo/generate-favicon-set.js +5 -6
- package/dist/app-logo/squircle.d.ts +49 -29
- package/dist/app-logo/squircle.js +153 -157
- package/dist/assets/logo-parts/glow-squircle.svg +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/leftium-logo/generate-favicon-svg.d.ts +27 -0
- package/dist/leftium-logo/generate-favicon-svg.js +90 -0
- package/dist/leftium-logo/generate-svg.js +11 -275
- package/dist/leftium-logo/generate-zip-kit.d.ts +21 -0
- package/dist/leftium-logo/generate-zip-kit.js +55 -0
- package/dist/leftium-logo/l-ligature.d.ts +40 -0
- package/dist/leftium-logo/l-ligature.js +77 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
-
<!-- Squircle variant of glow (50% radius, K=2 superellipse) -->
|
|
2
|
+
<!-- Squircle variant of glow (50% radius, K=2 superellipse, true Lame curve) -->
|
|
3
3
|
|
|
4
4
|
<svg
|
|
5
5
|
width="1375.7469"
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
style="opacity:0.7;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3)"
|
|
38
38
|
id="path2"
|
|
39
39
|
transform="translate(-8.6700182, 0.25409326)"
|
|
40
|
-
d="M565.
|
|
40
|
+
d="M565.68,0 L654.3,0.09 L690.99,0.34 L719.11,0.77 L742.79,1.36 L763.6,2.13 L782.37,3.07 L799.58,4.18 L815.54,5.46 L830.47,6.91 L844.53,8.54 L857.83,10.34 L870.47,12.31 L882.51,14.46 L894.02,16.78 L905.05,19.28 L915.63,21.96 L925.79,24.81 L935.57,27.84 L944.99,31.05 L954.07,34.45 L962.83,38.02 L971.29,41.78 L979.45,45.73 L987.33,49.87 L994.94,54.19 L1002.29,58.71 L1009.39,63.42 L1016.25,68.33 L1022.87,73.44 L1029.26,78.75 L1035.42,84.27 L1041.37,90 L1047.1,95.95 L1052.62,102.11 L1057.93,108.5 L1063.04,115.12 L1067.95,121.98 L1072.66,129.08 L1077.18,136.43 L1081.5,144.04 L1085.64,151.92 L1089.59,160.08 L1093.35,168.54 L1096.92,177.3 L1100.32,186.38 L1103.53,195.8 L1106.56,205.58 L1109.41,215.74 L1112.09,226.32 L1114.59,237.35 L1116.91,248.86 L1119.06,260.9 L1121.03,273.54 L1122.83,286.84 L1124.46,300.9 L1125.91,315.83 L1127.19,331.79 L1128.3,349 L1129.24,367.77 L1130.01,388.58 L1130.6,412.26 L1131.03,440.38 L1131.28,477.07 L1131.37,565.68 L1131.37,565.68 L1131.28,654.3 L1131.03,690.99 L1130.6,719.11 L1130.01,742.79 L1129.24,763.6 L1128.3,782.37 L1127.19,799.58 L1125.91,815.54 L1124.46,830.47 L1122.83,844.53 L1121.03,857.83 L1119.06,870.47 L1116.91,882.51 L1114.59,894.02 L1112.09,905.05 L1109.41,915.63 L1106.56,925.79 L1103.53,935.57 L1100.32,944.99 L1096.92,954.07 L1093.35,962.83 L1089.59,971.29 L1085.64,979.45 L1081.5,987.33 L1077.18,994.94 L1072.66,1002.29 L1067.95,1009.39 L1063.04,1016.25 L1057.93,1022.87 L1052.62,1029.26 L1047.1,1035.42 L1041.37,1041.37 L1035.42,1047.1 L1029.26,1052.62 L1022.87,1057.93 L1016.25,1063.04 L1009.39,1067.95 L1002.29,1072.66 L994.94,1077.18 L987.33,1081.5 L979.45,1085.64 L971.29,1089.59 L962.83,1093.35 L954.07,1096.92 L944.99,1100.32 L935.57,1103.53 L925.79,1106.56 L915.63,1109.41 L905.05,1112.09 L894.02,1114.59 L882.51,1116.91 L870.47,1119.06 L857.83,1121.03 L844.53,1122.83 L830.47,1124.46 L815.54,1125.91 L799.58,1127.19 L782.37,1128.3 L763.6,1129.24 L742.79,1130.01 L719.11,1130.6 L690.99,1131.03 L654.3,1131.28 L565.68,1131.37 L565.68,1131.37 L477.07,1131.28 L440.38,1131.03 L412.26,1130.6 L388.58,1130.01 L367.77,1129.24 L349,1128.3 L331.79,1127.19 L315.83,1125.91 L300.9,1124.46 L286.84,1122.83 L273.54,1121.03 L260.9,1119.06 L248.86,1116.91 L237.35,1114.59 L226.32,1112.09 L215.74,1109.41 L205.58,1106.56 L195.8,1103.53 L186.38,1100.32 L177.3,1096.92 L168.54,1093.35 L160.08,1089.59 L151.92,1085.64 L144.04,1081.5 L136.43,1077.18 L129.08,1072.66 L121.98,1067.95 L115.12,1063.04 L108.5,1057.93 L102.11,1052.62 L95.95,1047.1 L90,1041.37 L84.27,1035.42 L78.75,1029.26 L73.44,1022.87 L68.33,1016.25 L63.42,1009.39 L58.71,1002.29 L54.19,994.94 L49.87,987.33 L45.73,979.45 L41.78,971.29 L38.02,962.83 L34.45,954.07 L31.05,944.99 L27.84,935.57 L24.81,925.79 L21.96,915.63 L19.28,905.05 L16.78,894.02 L14.46,882.51 L12.31,870.47 L10.34,857.83 L8.54,844.53 L6.91,830.47 L5.46,815.54 L4.18,799.58 L3.07,782.37 L2.13,763.6 L1.36,742.79 L0.77,719.11 L0.34,690.99 L0.09,654.3 L0,565.68 L0,565.68 L0.09,477.07 L0.34,440.38 L0.77,412.26 L1.36,388.58 L2.13,367.77 L3.07,349 L4.18,331.79 L5.46,315.83 L6.91,300.9 L8.54,286.84 L10.34,273.54 L12.31,260.9 L14.46,248.86 L16.78,237.35 L19.28,226.32 L21.96,215.74 L24.81,205.58 L27.84,195.8 L31.05,186.38 L34.45,177.3 L38.02,168.54 L41.78,160.08 L45.73,151.92 L49.87,144.04 L54.19,136.43 L58.71,129.08 L63.42,121.98 L68.33,115.12 L73.44,108.5 L78.75,102.11 L84.27,95.95 L90,90 L95.95,84.27 L102.11,78.75 L108.5,73.44 L115.12,68.33 L121.98,63.42 L129.08,58.71 L136.43,54.19 L144.04,49.87 L151.92,45.73 L160.08,41.78 L168.54,38.02 L177.3,34.45 L186.38,31.05 L195.8,27.84 L205.58,24.81 L215.74,21.96 L226.32,19.28 L237.35,16.78 L248.86,14.46 L260.9,12.31 L273.54,10.34 L286.84,8.54 L300.9,6.91 L315.83,5.46 L331.79,4.18 L349,3.07 L367.77,2.13 L388.58,1.36 L412.26,0.77 L440.38,0.34 L477.07,0.09 L565.68,0 Z" />
|
|
41
41
|
</g>
|
|
42
42
|
</g>
|
|
43
43
|
</g>
|
package/dist/index.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export type { AppLogoProps, AppLogoConfig, GradientConfig, IconColorMode, Corner
|
|
|
6
6
|
export { generateAppLogoSvg } from './app-logo/generate-svg.js';
|
|
7
7
|
export { generateAppLogoPng } from './app-logo/generate-png.js';
|
|
8
8
|
export { LEFTIUM_GRADIENT } from './app-logo/defaults.js';
|
|
9
|
-
export { generateCornerPath, cornerShapeToK } from './app-logo/squircle.js';
|
|
9
|
+
export { generateCornerPath, generateCornerPolygon, generateCornerPolygonPoints, cornerShapeToK } from './app-logo/squircle.js';
|
|
10
10
|
export { applyColorMode } from './app-logo/color-transform.js';
|
package/dist/index.js
CHANGED
|
@@ -8,5 +8,5 @@ export { generateAppLogoSvg } from './app-logo/generate-svg.js';
|
|
|
8
8
|
export { generateAppLogoPng } from './app-logo/generate-png.js';
|
|
9
9
|
export { LEFTIUM_GRADIENT } from './app-logo/defaults.js';
|
|
10
10
|
// Phase 2: Advanced styling utilities
|
|
11
|
-
export { generateCornerPath, cornerShapeToK } from './app-logo/squircle.js';
|
|
11
|
+
export { generateCornerPath, generateCornerPolygon, generateCornerPolygonPoints, cornerShapeToK } from './app-logo/squircle.js';
|
|
12
12
|
export { applyColorMode } from './app-logo/color-transform.js';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a self-contained SVG for the Leftium favicon.
|
|
3
|
+
*
|
|
4
|
+
* Renders the rotated "L" ligature (filled white polygon) on the
|
|
5
|
+
* Leftium brand gradient, with either a square or squircle shape.
|
|
6
|
+
*/
|
|
7
|
+
export interface FaviconConfig {
|
|
8
|
+
/** Output size in pixels. Default: 128 */
|
|
9
|
+
size?: number;
|
|
10
|
+
/** Use squircle shape. Default: false (square) */
|
|
11
|
+
squircle?: boolean;
|
|
12
|
+
/** Ligature scale (1 = default fit). Default: 1 */
|
|
13
|
+
ligatureScale?: number;
|
|
14
|
+
/** Ligature horizontal offset as fraction of container. Default: 0 */
|
|
15
|
+
ligatureOffsetX?: number;
|
|
16
|
+
/** Ligature vertical offset as fraction of container. Default: 0 */
|
|
17
|
+
ligatureOffsetY?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generate a self-contained SVG string for the Leftium favicon.
|
|
21
|
+
*/
|
|
22
|
+
export declare function generateFaviconSvg(config?: FaviconConfig): string;
|
|
23
|
+
/**
|
|
24
|
+
* Rasterize the favicon to a PNG or WebP Blob.
|
|
25
|
+
* Browser-only (requires canvas + Image).
|
|
26
|
+
*/
|
|
27
|
+
export declare function generateFaviconPng(config: FaviconConfig, format?: 'png' | 'webp'): Promise<Blob>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a self-contained SVG for the Leftium favicon.
|
|
3
|
+
*
|
|
4
|
+
* Renders the rotated "L" ligature (filled white polygon) on the
|
|
5
|
+
* Leftium brand gradient, with either a square or squircle shape.
|
|
6
|
+
*/
|
|
7
|
+
import { generateCornerPath } from '../app-logo/squircle.js';
|
|
8
|
+
import { generateLPolygonPoints } from './l-ligature.js';
|
|
9
|
+
// ─── Leftium brand gradient ─────────────────────────────────────────────────
|
|
10
|
+
const GRAD_STOPS = [
|
|
11
|
+
{ offset: 0, color: '#0029c1' },
|
|
12
|
+
{ offset: 0.29, color: '#3973ff' },
|
|
13
|
+
{ offset: 1, color: '#0029c1' }
|
|
14
|
+
];
|
|
15
|
+
// ─── SVG Generation ──────────────────────────────────────────────────────────
|
|
16
|
+
/**
|
|
17
|
+
* Generate a self-contained SVG string for the Leftium favicon.
|
|
18
|
+
*/
|
|
19
|
+
export function generateFaviconSvg(config = {}) {
|
|
20
|
+
const { size = 128, squircle = false, ligatureScale = 1, ligatureOffsetX = 0, ligatureOffsetY = 0 } = config;
|
|
21
|
+
// ── Background shape ─────────────────────────────────────────────────────
|
|
22
|
+
let bgPath;
|
|
23
|
+
if (squircle) {
|
|
24
|
+
// Squircle: 50% radius, K=2 superellipse
|
|
25
|
+
bgPath = generateCornerPath(size, 50, 'squircle');
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
bgPath = `M0,0 H${size} V${size} H0 Z`;
|
|
29
|
+
}
|
|
30
|
+
// ── Gradient (45° diagonal, bottom-left to top-right) ────────────────────
|
|
31
|
+
const gradStops = GRAD_STOPS.map((s) => `<stop offset="${s.offset * 100}%" stop-color="${s.color}"/>`).join('\n ');
|
|
32
|
+
// ── L ligature polygon ───────────────────────────────────────────────────
|
|
33
|
+
const polygonPoints = generateLPolygonPoints(size, ligatureScale, ligatureOffsetX, ligatureOffsetY);
|
|
34
|
+
// ── Assemble SVG ─────────────────────────────────────────────────────────
|
|
35
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}">
|
|
36
|
+
<defs>
|
|
37
|
+
<linearGradient id="g" x1="0%" y1="100%" x2="100%" y2="0%">
|
|
38
|
+
${gradStops}
|
|
39
|
+
</linearGradient>
|
|
40
|
+
<clipPath id="shape">
|
|
41
|
+
<path d="${bgPath}"/>
|
|
42
|
+
</clipPath>
|
|
43
|
+
</defs>
|
|
44
|
+
<rect width="${size}" height="${size}" fill="url(#g)" clip-path="url(#shape)"/>
|
|
45
|
+
<polygon points="${polygonPoints}" fill="white" clip-path="url(#shape)"/>
|
|
46
|
+
</svg>`;
|
|
47
|
+
}
|
|
48
|
+
// ─── PNG / WebP rasterizer ───────────────────────────────────────────────────
|
|
49
|
+
/**
|
|
50
|
+
* Rasterize the favicon to a PNG or WebP Blob.
|
|
51
|
+
* Browser-only (requires canvas + Image).
|
|
52
|
+
*/
|
|
53
|
+
export async function generateFaviconPng(config, format = 'png') {
|
|
54
|
+
const svg = generateFaviconSvg(config);
|
|
55
|
+
const size = config.size ?? 128;
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
const img = new Image();
|
|
58
|
+
const blob = new Blob([svg], { type: 'image/svg+xml;charset=utf-8' });
|
|
59
|
+
const url = URL.createObjectURL(blob);
|
|
60
|
+
img.onload = () => {
|
|
61
|
+
try {
|
|
62
|
+
const canvas = document.createElement('canvas');
|
|
63
|
+
canvas.width = size;
|
|
64
|
+
canvas.height = size;
|
|
65
|
+
const ctx = canvas.getContext('2d');
|
|
66
|
+
if (!ctx) {
|
|
67
|
+
reject(new Error('Failed to get canvas 2d context'));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
ctx.drawImage(img, 0, 0, size, size);
|
|
71
|
+
canvas.toBlob((outBlob) => {
|
|
72
|
+
URL.revokeObjectURL(url);
|
|
73
|
+
if (outBlob)
|
|
74
|
+
resolve(outBlob);
|
|
75
|
+
else
|
|
76
|
+
reject(new Error('Canvas toBlob returned null'));
|
|
77
|
+
}, format === 'webp' ? 'image/webp' : 'image/png');
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
URL.revokeObjectURL(url);
|
|
81
|
+
reject(err);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
img.onerror = () => {
|
|
85
|
+
URL.revokeObjectURL(url);
|
|
86
|
+
reject(new Error('Failed to load SVG into Image element'));
|
|
87
|
+
};
|
|
88
|
+
img.src = url;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
@@ -10,6 +10,7 @@ import glowSvgRaw from '../assets/logo-parts/glow.svg?raw';
|
|
|
10
10
|
import glowSquircleSvgRaw from '../assets/logo-parts/glow-squircle.svg?raw';
|
|
11
11
|
import ligatureSvgRaw from '../assets/logo-parts/ligature.svg?raw';
|
|
12
12
|
import shadowSvgRaw from '../assets/logo-parts/shadow.svg?raw';
|
|
13
|
+
import { generateCornerPath } from '../app-logo/squircle.js';
|
|
13
14
|
// ─── Geometry constants (mirrored from LeftiumLogo.svelte) ───────────────────
|
|
14
15
|
// The inner grid (grid-logo) is always 532×532 in "native" units.
|
|
15
16
|
const GRID = 532;
|
|
@@ -22,12 +23,12 @@ const LIG_ORIG_H = 666;
|
|
|
22
23
|
const LIG_ORIG_L = 133.5;
|
|
23
24
|
const LIG_ORIG_T = -65.75;
|
|
24
25
|
const BLUR_PAD_ORIG = 50;
|
|
25
|
-
// Ligature positioning — squircle mode
|
|
26
|
-
const LIG_SQRC_W =
|
|
27
|
-
const LIG_SQRC_H =
|
|
28
|
-
const LIG_SQRC_L =
|
|
29
|
-
const LIG_SQRC_T = -
|
|
30
|
-
const BLUR_PAD_SQRC =
|
|
26
|
+
// Ligature positioning — squircle mode (true Lamé squircle boundary)
|
|
27
|
+
const LIG_SQRC_W = 405.2;
|
|
28
|
+
const LIG_SQRC_H = 613.6;
|
|
29
|
+
const LIG_SQRC_L = 121.4;
|
|
30
|
+
const LIG_SQRC_T = -19.8;
|
|
31
|
+
const BLUR_PAD_SQRC = 46.0;
|
|
31
32
|
// Bounding box scaling factors for the grid within the output canvas.
|
|
32
33
|
// CSS: grid width = canvas / scale_factor, centered.
|
|
33
34
|
const BBOX_SCALE = {
|
|
@@ -44,271 +45,6 @@ const CROPPED_ASPECT = 1 / 0.8906; // height = width * this
|
|
|
44
45
|
const CROPPED_GRID_W_FRAC = 0.782; // grid is 78.2% of container width
|
|
45
46
|
const CROPPED_LEFT_FRAC = 0.0844; // 8.44% from left
|
|
46
47
|
const CROPPED_TOP_FRAC = 0.1523; // 15.23% from top
|
|
47
|
-
// Squircle clip polygon points (percentages → will be scaled to px).
|
|
48
|
-
// This is the same polygon as LeftiumLogo.svelte SQUIRCLE_CLIP but converted
|
|
49
|
-
// to absolute pixel coordinates at render time.
|
|
50
|
-
const SQUIRCLE_POLY_PCTS = [
|
|
51
|
-
[50, 0],
|
|
52
|
-
[53.05, 0],
|
|
53
|
-
[55.96, 0],
|
|
54
|
-
[58.74, 0],
|
|
55
|
-
[61.38, 0],
|
|
56
|
-
[63.89, 0],
|
|
57
|
-
[66.27, 0],
|
|
58
|
-
[68.54, 0.01],
|
|
59
|
-
[70.69, 0.01],
|
|
60
|
-
[72.73, 0.02],
|
|
61
|
-
[74.66, 0.03],
|
|
62
|
-
[76.48, 0.04],
|
|
63
|
-
[78.21, 0.06],
|
|
64
|
-
[79.84, 0.09],
|
|
65
|
-
[81.37, 0.11],
|
|
66
|
-
[82.82, 0.15],
|
|
67
|
-
[84.18, 0.2],
|
|
68
|
-
[85.46, 0.25],
|
|
69
|
-
[86.66, 0.31],
|
|
70
|
-
[87.78, 0.39],
|
|
71
|
-
[88.83, 0.48],
|
|
72
|
-
[89.81, 0.58],
|
|
73
|
-
[90.73, 0.7],
|
|
74
|
-
[91.58, 0.83],
|
|
75
|
-
[92.37, 0.99],
|
|
76
|
-
[93.11, 1.16],
|
|
77
|
-
[93.79, 1.36],
|
|
78
|
-
[94.41, 1.58],
|
|
79
|
-
[94.99, 1.83],
|
|
80
|
-
[95.53, 2.11],
|
|
81
|
-
[96.02, 2.41],
|
|
82
|
-
[96.47, 2.75],
|
|
83
|
-
[96.88, 3.13],
|
|
84
|
-
[97.25, 3.53],
|
|
85
|
-
[97.59, 3.98],
|
|
86
|
-
[97.89, 4.47],
|
|
87
|
-
[98.17, 5.01],
|
|
88
|
-
[98.42, 5.59],
|
|
89
|
-
[98.64, 6.21],
|
|
90
|
-
[98.84, 6.89],
|
|
91
|
-
[99.01, 7.63],
|
|
92
|
-
[99.17, 8.42],
|
|
93
|
-
[99.3, 9.27],
|
|
94
|
-
[99.42, 10.19],
|
|
95
|
-
[99.52, 11.17],
|
|
96
|
-
[99.61, 12.22],
|
|
97
|
-
[99.69, 13.34],
|
|
98
|
-
[99.75, 14.54],
|
|
99
|
-
[99.8, 15.82],
|
|
100
|
-
[99.85, 17.18],
|
|
101
|
-
[99.89, 18.63],
|
|
102
|
-
[99.91, 20.16],
|
|
103
|
-
[99.94, 21.79],
|
|
104
|
-
[99.96, 23.52],
|
|
105
|
-
[99.97, 25.34],
|
|
106
|
-
[99.98, 27.27],
|
|
107
|
-
[99.99, 29.31],
|
|
108
|
-
[99.99, 31.46],
|
|
109
|
-
[100, 33.73],
|
|
110
|
-
[100, 36.11],
|
|
111
|
-
[100, 38.62],
|
|
112
|
-
[100, 41.26],
|
|
113
|
-
[100, 44.04],
|
|
114
|
-
[100, 46.95],
|
|
115
|
-
[100, 50],
|
|
116
|
-
[100, 50],
|
|
117
|
-
[100, 53.05],
|
|
118
|
-
[100, 55.96],
|
|
119
|
-
[100, 58.74],
|
|
120
|
-
[100, 61.38],
|
|
121
|
-
[100, 63.89],
|
|
122
|
-
[100, 66.27],
|
|
123
|
-
[99.99, 68.54],
|
|
124
|
-
[99.99, 70.69],
|
|
125
|
-
[99.98, 72.73],
|
|
126
|
-
[99.97, 74.66],
|
|
127
|
-
[99.96, 76.48],
|
|
128
|
-
[99.94, 78.21],
|
|
129
|
-
[99.91, 79.84],
|
|
130
|
-
[99.89, 81.37],
|
|
131
|
-
[99.85, 82.82],
|
|
132
|
-
[99.8, 84.18],
|
|
133
|
-
[99.75, 85.46],
|
|
134
|
-
[99.69, 86.66],
|
|
135
|
-
[99.61, 87.78],
|
|
136
|
-
[99.52, 88.83],
|
|
137
|
-
[99.42, 89.81],
|
|
138
|
-
[99.3, 90.73],
|
|
139
|
-
[99.17, 91.58],
|
|
140
|
-
[99.01, 92.37],
|
|
141
|
-
[98.84, 93.11],
|
|
142
|
-
[98.64, 93.79],
|
|
143
|
-
[98.42, 94.41],
|
|
144
|
-
[98.17, 94.99],
|
|
145
|
-
[97.89, 95.53],
|
|
146
|
-
[97.59, 96.02],
|
|
147
|
-
[97.25, 96.47],
|
|
148
|
-
[96.88, 96.88],
|
|
149
|
-
[96.47, 97.25],
|
|
150
|
-
[96.02, 97.59],
|
|
151
|
-
[95.53, 97.89],
|
|
152
|
-
[94.99, 98.17],
|
|
153
|
-
[94.41, 98.42],
|
|
154
|
-
[93.79, 98.64],
|
|
155
|
-
[93.11, 98.84],
|
|
156
|
-
[92.37, 99.01],
|
|
157
|
-
[91.58, 99.17],
|
|
158
|
-
[90.73, 99.3],
|
|
159
|
-
[89.81, 99.42],
|
|
160
|
-
[88.83, 99.52],
|
|
161
|
-
[87.78, 99.61],
|
|
162
|
-
[86.66, 99.69],
|
|
163
|
-
[85.46, 99.75],
|
|
164
|
-
[84.18, 99.8],
|
|
165
|
-
[82.82, 99.85],
|
|
166
|
-
[81.37, 99.89],
|
|
167
|
-
[79.84, 99.91],
|
|
168
|
-
[78.21, 99.94],
|
|
169
|
-
[76.48, 99.96],
|
|
170
|
-
[74.66, 99.97],
|
|
171
|
-
[72.73, 99.98],
|
|
172
|
-
[70.69, 99.99],
|
|
173
|
-
[68.54, 99.99],
|
|
174
|
-
[66.27, 100],
|
|
175
|
-
[63.89, 100],
|
|
176
|
-
[61.38, 100],
|
|
177
|
-
[58.74, 100],
|
|
178
|
-
[55.96, 100],
|
|
179
|
-
[53.05, 100],
|
|
180
|
-
[50, 100],
|
|
181
|
-
[50, 100],
|
|
182
|
-
[46.95, 100],
|
|
183
|
-
[44.04, 100],
|
|
184
|
-
[41.26, 100],
|
|
185
|
-
[38.62, 100],
|
|
186
|
-
[36.11, 100],
|
|
187
|
-
[33.73, 100],
|
|
188
|
-
[31.46, 99.99],
|
|
189
|
-
[29.31, 99.99],
|
|
190
|
-
[27.27, 99.98],
|
|
191
|
-
[25.34, 99.97],
|
|
192
|
-
[23.52, 99.96],
|
|
193
|
-
[21.79, 99.94],
|
|
194
|
-
[20.16, 99.91],
|
|
195
|
-
[18.63, 99.89],
|
|
196
|
-
[17.18, 99.85],
|
|
197
|
-
[15.82, 99.8],
|
|
198
|
-
[14.54, 99.75],
|
|
199
|
-
[13.34, 99.69],
|
|
200
|
-
[12.22, 99.61],
|
|
201
|
-
[11.17, 99.52],
|
|
202
|
-
[10.19, 99.42],
|
|
203
|
-
[9.27, 99.3],
|
|
204
|
-
[8.42, 99.17],
|
|
205
|
-
[7.63, 99.01],
|
|
206
|
-
[6.89, 98.84],
|
|
207
|
-
[6.21, 98.64],
|
|
208
|
-
[5.59, 98.42],
|
|
209
|
-
[5.01, 98.17],
|
|
210
|
-
[4.47, 97.89],
|
|
211
|
-
[3.98, 97.59],
|
|
212
|
-
[3.53, 97.25],
|
|
213
|
-
[3.13, 96.88],
|
|
214
|
-
[2.75, 96.47],
|
|
215
|
-
[2.41, 96.02],
|
|
216
|
-
[2.11, 95.53],
|
|
217
|
-
[1.83, 94.99],
|
|
218
|
-
[1.58, 94.41],
|
|
219
|
-
[1.36, 93.79],
|
|
220
|
-
[1.16, 93.11],
|
|
221
|
-
[0.99, 92.37],
|
|
222
|
-
[0.83, 91.58],
|
|
223
|
-
[0.7, 90.73],
|
|
224
|
-
[0.58, 89.81],
|
|
225
|
-
[0.48, 88.83],
|
|
226
|
-
[0.39, 87.78],
|
|
227
|
-
[0.31, 86.66],
|
|
228
|
-
[0.25, 85.46],
|
|
229
|
-
[0.2, 84.18],
|
|
230
|
-
[0.15, 82.82],
|
|
231
|
-
[0.11, 81.37],
|
|
232
|
-
[0.09, 79.84],
|
|
233
|
-
[0.06, 78.21],
|
|
234
|
-
[0.04, 76.48],
|
|
235
|
-
[0.03, 74.66],
|
|
236
|
-
[0.02, 72.73],
|
|
237
|
-
[0.01, 70.69],
|
|
238
|
-
[0.01, 68.54],
|
|
239
|
-
[0, 66.27],
|
|
240
|
-
[0, 63.89],
|
|
241
|
-
[0, 61.38],
|
|
242
|
-
[0, 58.74],
|
|
243
|
-
[0, 55.96],
|
|
244
|
-
[0, 53.05],
|
|
245
|
-
[0, 50],
|
|
246
|
-
[0, 50],
|
|
247
|
-
[0, 46.95],
|
|
248
|
-
[0, 44.04],
|
|
249
|
-
[0, 41.26],
|
|
250
|
-
[0, 38.62],
|
|
251
|
-
[0, 36.11],
|
|
252
|
-
[0, 33.73],
|
|
253
|
-
[0.01, 31.46],
|
|
254
|
-
[0.01, 29.31],
|
|
255
|
-
[0.02, 27.27],
|
|
256
|
-
[0.03, 25.34],
|
|
257
|
-
[0.04, 23.52],
|
|
258
|
-
[0.06, 21.79],
|
|
259
|
-
[0.09, 20.16],
|
|
260
|
-
[0.11, 18.63],
|
|
261
|
-
[0.15, 17.18],
|
|
262
|
-
[0.2, 15.82],
|
|
263
|
-
[0.25, 14.54],
|
|
264
|
-
[0.31, 13.34],
|
|
265
|
-
[0.39, 12.22],
|
|
266
|
-
[0.48, 11.17],
|
|
267
|
-
[0.58, 10.19],
|
|
268
|
-
[0.7, 9.27],
|
|
269
|
-
[0.83, 8.42],
|
|
270
|
-
[0.99, 7.63],
|
|
271
|
-
[1.16, 6.89],
|
|
272
|
-
[1.36, 6.21],
|
|
273
|
-
[1.58, 5.59],
|
|
274
|
-
[1.83, 5.01],
|
|
275
|
-
[2.11, 4.47],
|
|
276
|
-
[2.41, 3.98],
|
|
277
|
-
[2.75, 3.53],
|
|
278
|
-
[3.13, 3.13],
|
|
279
|
-
[3.53, 2.75],
|
|
280
|
-
[3.98, 2.41],
|
|
281
|
-
[4.47, 2.11],
|
|
282
|
-
[5.01, 1.83],
|
|
283
|
-
[5.59, 1.58],
|
|
284
|
-
[6.21, 1.36],
|
|
285
|
-
[6.89, 1.16],
|
|
286
|
-
[7.63, 0.99],
|
|
287
|
-
[8.42, 0.83],
|
|
288
|
-
[9.27, 0.7],
|
|
289
|
-
[10.19, 0.58],
|
|
290
|
-
[11.17, 0.48],
|
|
291
|
-
[12.22, 0.39],
|
|
292
|
-
[13.34, 0.31],
|
|
293
|
-
[14.54, 0.25],
|
|
294
|
-
[15.82, 0.2],
|
|
295
|
-
[17.18, 0.15],
|
|
296
|
-
[18.63, 0.11],
|
|
297
|
-
[20.16, 0.09],
|
|
298
|
-
[21.79, 0.06],
|
|
299
|
-
[23.52, 0.04],
|
|
300
|
-
[25.34, 0.03],
|
|
301
|
-
[27.27, 0.02],
|
|
302
|
-
[29.31, 0.01],
|
|
303
|
-
[31.46, 0.01],
|
|
304
|
-
[33.73, 0],
|
|
305
|
-
[36.11, 0],
|
|
306
|
-
[38.62, 0],
|
|
307
|
-
[41.26, 0],
|
|
308
|
-
[44.04, 0],
|
|
309
|
-
[46.95, 0],
|
|
310
|
-
[50, 0]
|
|
311
|
-
];
|
|
312
48
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
313
49
|
/** Encode a raw SVG string as a base64 data URI */
|
|
314
50
|
function svgToDataUri(svgRaw) {
|
|
@@ -321,12 +57,12 @@ function r(n) {
|
|
|
321
57
|
return Math.round(n * 10000) / 10000;
|
|
322
58
|
}
|
|
323
59
|
/**
|
|
324
|
-
*
|
|
325
|
-
*
|
|
60
|
+
* Build an SVG `<clipPath>` for the squircle, offset by (ox, oy) within the canvas.
|
|
61
|
+
* Uses `generateCornerPath` for the true Lamé curve, then translates to position.
|
|
326
62
|
*/
|
|
327
63
|
function squircleClipPath(gridPx, ox, oy, clipId) {
|
|
328
|
-
const
|
|
329
|
-
return `<clipPath id="${clipId}"><
|
|
64
|
+
const pathD = generateCornerPath(gridPx, 50, 'squircle');
|
|
65
|
+
return `<clipPath id="${clipId}"><path d="${pathD}" transform="translate(${r(ox)},${r(oy)})"/></clipPath>`;
|
|
330
66
|
}
|
|
331
67
|
// ─── Main export ─────────────────────────────────────────────────────────────
|
|
332
68
|
/**
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { LeftiumLogoConfig } from './generate-svg.js';
|
|
2
|
+
import type { FaviconConfig } from './generate-favicon-svg.js';
|
|
3
|
+
import { type AppInfo } from '../app-logo/generate-favicon-set.js';
|
|
4
|
+
export type { AppInfo };
|
|
5
|
+
/**
|
|
6
|
+
* Build the full Leftium logo kit as a zip Blob.
|
|
7
|
+
*
|
|
8
|
+
* Zip structure mirrors a SvelteKit project root:
|
|
9
|
+
* static/favicon.ico (32×32 favicon PNG wrapped in ICO container)
|
|
10
|
+
* static/icon.svg (favicon SVG)
|
|
11
|
+
* static/apple-touch-icon.png (180×180 favicon PNG)
|
|
12
|
+
* static/icon-192.png (192×192 favicon PNG)
|
|
13
|
+
* static/icon-512.png (512×512 favicon PNG)
|
|
14
|
+
* static/logo.png (512px logo PNG)
|
|
15
|
+
* static/logo.webp (512px logo WebP)
|
|
16
|
+
* static/logo.svg (logo SVG)
|
|
17
|
+
* static/manifest.webmanifest (PWA web app manifest)
|
|
18
|
+
* .logo/config.json (logo + favicon config for regeneration)
|
|
19
|
+
* .logo/favicon.htm (HTML <head> snippet, paste-ready)
|
|
20
|
+
*/
|
|
21
|
+
export declare function generateLeftiumZipKit(logoConfig: LeftiumLogoConfig, faviconConfig: FaviconConfig, appInfo?: AppInfo): Promise<Blob>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import JSZip from 'jszip';
|
|
2
|
+
import { generateLeftiumLogoSvg, generateLeftiumLogoPng } from './generate-svg.js';
|
|
3
|
+
import { generateFaviconSvg, generateFaviconPng } from './generate-favicon-svg.js';
|
|
4
|
+
import { pngToIco } from '../app-logo/generate-ico.js';
|
|
5
|
+
import { generateManifest, generateFaviconHtml } from '../app-logo/generate-favicon-set.js';
|
|
6
|
+
/**
|
|
7
|
+
* Build the full Leftium logo kit as a zip Blob.
|
|
8
|
+
*
|
|
9
|
+
* Zip structure mirrors a SvelteKit project root:
|
|
10
|
+
* static/favicon.ico (32×32 favicon PNG wrapped in ICO container)
|
|
11
|
+
* static/icon.svg (favicon SVG)
|
|
12
|
+
* static/apple-touch-icon.png (180×180 favicon PNG)
|
|
13
|
+
* static/icon-192.png (192×192 favicon PNG)
|
|
14
|
+
* static/icon-512.png (512×512 favicon PNG)
|
|
15
|
+
* static/logo.png (512px logo PNG)
|
|
16
|
+
* static/logo.webp (512px logo WebP)
|
|
17
|
+
* static/logo.svg (logo SVG)
|
|
18
|
+
* static/manifest.webmanifest (PWA web app manifest)
|
|
19
|
+
* .logo/config.json (logo + favicon config for regeneration)
|
|
20
|
+
* .logo/favicon.htm (HTML <head> snippet, paste-ready)
|
|
21
|
+
*/
|
|
22
|
+
export async function generateLeftiumZipKit(logoConfig, faviconConfig, appInfo = { name: 'Leftium', shortName: 'Leftium' }) {
|
|
23
|
+
// Generate favicon PNGs at all required sizes in parallel with logo assets
|
|
24
|
+
const [logoPng, logoWebp, logoSvg, faviconPng32, faviconAppleTouch, favicon192, favicon512] = await Promise.all([
|
|
25
|
+
generateLeftiumLogoPng({ ...logoConfig, size: 512 }, 'png'),
|
|
26
|
+
generateLeftiumLogoPng({ ...logoConfig, size: 512 }, 'webp'),
|
|
27
|
+
generateLeftiumLogoSvg(logoConfig),
|
|
28
|
+
generateFaviconPng({ ...faviconConfig, size: 32 }, 'png'),
|
|
29
|
+
generateFaviconPng({ ...faviconConfig, size: 180 }, 'png'),
|
|
30
|
+
generateFaviconPng({ ...faviconConfig, size: 192 }, 'png'),
|
|
31
|
+
generateFaviconPng({ ...faviconConfig, size: 512 }, 'png')
|
|
32
|
+
]);
|
|
33
|
+
const faviconIco = await pngToIco(faviconPng32);
|
|
34
|
+
const faviconSvg = generateFaviconSvg(faviconConfig);
|
|
35
|
+
const zip = new JSZip();
|
|
36
|
+
const staticDir = zip.folder('static');
|
|
37
|
+
const logoDir = zip.folder('.logo');
|
|
38
|
+
// Favicon files
|
|
39
|
+
staticDir.file('favicon.ico', faviconIco);
|
|
40
|
+
staticDir.file('icon.svg', faviconSvg);
|
|
41
|
+
staticDir.file('apple-touch-icon.png', faviconAppleTouch);
|
|
42
|
+
staticDir.file('icon-192.png', favicon192);
|
|
43
|
+
staticDir.file('icon-512.png', favicon512);
|
|
44
|
+
// Logo files
|
|
45
|
+
staticDir.file('logo.png', logoPng);
|
|
46
|
+
staticDir.file('logo.webp', logoWebp);
|
|
47
|
+
staticDir.file('logo.svg', logoSvg);
|
|
48
|
+
// Manifest
|
|
49
|
+
staticDir.file('manifest.webmanifest', generateManifest(appInfo));
|
|
50
|
+
// Config for regeneration
|
|
51
|
+
logoDir.file('config.json', JSON.stringify({ logo: logoConfig, favicon: faviconConfig }, null, '\t'));
|
|
52
|
+
// HTML snippet
|
|
53
|
+
logoDir.file('favicon.htm', generateFaviconHtml(appInfo));
|
|
54
|
+
return zip.generateAsync({ type: 'blob' });
|
|
55
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L-only ligature geometry for the Leftium favicon.
|
|
3
|
+
*
|
|
4
|
+
* The "L" is defined on a grid of 5 equal squares:
|
|
5
|
+
* - Vertical stem: 1 square wide, 5 squares tall
|
|
6
|
+
* - Horizontal foot: 3 squares wide (2 for L + 1 shared), 1 square tall
|
|
7
|
+
*
|
|
8
|
+
* Unrotated vertices (in grid units, origin at top-left):
|
|
9
|
+
* (0,0) → (1,0) → (1,4) → (3,4) → (3,5) → (0,5)
|
|
10
|
+
*
|
|
11
|
+
* The shape is then rotated 45° clockwise for the final favicon mark.
|
|
12
|
+
*/
|
|
13
|
+
/** Vertices of the L shape in grid units before rotation. */
|
|
14
|
+
export declare const L_VERTICES: [number, number][];
|
|
15
|
+
/** Grid columns (unrotated width in grid units). */
|
|
16
|
+
export declare const L_COLS = 3;
|
|
17
|
+
/** Grid rows (unrotated height in grid units). */
|
|
18
|
+
export declare const L_ROWS = 5;
|
|
19
|
+
/** Rotated L vertices (in grid units, not yet translated to origin). */
|
|
20
|
+
export declare const L_ROTATED_RAW: [number, number][];
|
|
21
|
+
/** Width of rotated L bounding box (in grid units). */
|
|
22
|
+
export declare const L_ROTATED_W: number;
|
|
23
|
+
/** Height of rotated L bounding box (in grid units). */
|
|
24
|
+
export declare const L_ROTATED_H: number;
|
|
25
|
+
/** Rotated L vertices, translated so bounding box starts at (0,0). */
|
|
26
|
+
export declare const L_ROTATED: [number, number][];
|
|
27
|
+
/** Center of the rotated L bounding box (in grid units, origin-translated). */
|
|
28
|
+
export declare const L_ROTATED_CX: number;
|
|
29
|
+
export declare const L_ROTATED_CY: number;
|
|
30
|
+
/**
|
|
31
|
+
* Generate an SVG `points` attribute string for the rotated L polygon,
|
|
32
|
+
* scaled and positioned within a container.
|
|
33
|
+
*
|
|
34
|
+
* @param containerSize - Side length of the square container (px)
|
|
35
|
+
* @param scale - Scale factor (1 = fill container width)
|
|
36
|
+
* @param offsetX - Horizontal offset as fraction of container (-0.5 to 0.5)
|
|
37
|
+
* @param offsetY - Vertical offset as fraction of container (-0.5 to 0.5)
|
|
38
|
+
* @returns SVG polygon `points` string
|
|
39
|
+
*/
|
|
40
|
+
export declare function generateLPolygonPoints(containerSize: number, scale?: number, offsetX?: number, offsetY?: number): string;
|