@principal-ai/logo-component 0.1.4 → 0.1.6

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.
@@ -0,0 +1,159 @@
1
+ import React, { useMemo, useRef, useState, useEffect } from "react";
2
+ import { layoutText } from "./strokeCharacters";
3
+ let globalIdCounter = 0;
4
+ /**
5
+ * Estimates path length from SVG path data.
6
+ */
7
+ function estimatePathLength(d) {
8
+ const coords = d.match(/-?\d+\.?\d*/g);
9
+ if (!coords || coords.length < 4)
10
+ return 100;
11
+ let totalLength = 0;
12
+ for (let i = 2; i < coords.length; i += 2) {
13
+ const x1 = parseFloat(coords[i - 2]);
14
+ const y1 = parseFloat(coords[i - 1]);
15
+ const x2 = parseFloat(coords[i]);
16
+ const y2 = parseFloat(coords[i + 1]);
17
+ totalLength += Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
18
+ }
19
+ return totalLength || 100;
20
+ }
21
+ /**
22
+ * Parse start and end points from path data
23
+ */
24
+ function getPathEndpoints(d) {
25
+ const coords = d.match(/-?\d+\.?\d*/g);
26
+ if (!coords || coords.length < 4) {
27
+ return { start: { x: 0, y: 0 }, end: { x: 0, y: 0 } };
28
+ }
29
+ return {
30
+ start: { x: parseFloat(coords[0]), y: parseFloat(coords[1]) },
31
+ end: { x: parseFloat(coords[coords.length - 2]), y: parseFloat(coords[coords.length - 1]) },
32
+ };
33
+ }
34
+ /**
35
+ * Seeded random for consistent chaos patterns
36
+ */
37
+ function seededRandom(seed) {
38
+ return () => {
39
+ seed = (seed * 1103515245 + 12345) & 0x7fffffff;
40
+ return seed / 0x7fffffff;
41
+ };
42
+ }
43
+ export const TextReveal = ({ text, width = 400, height = 100, scale = 1, letterSpacing = 4, centerText = true, chaosMode = "none", chaosDuration = 2, dotsDuration = 1.5, flowDuration = 2, flowDelay = 0.3, particlesPerPath = 1, particleRadius = 2.5, color = "currentColor", particleColor, strokeWidth = 2, opacity = 0.9, showGlow = true, fadeAfterAssembly = true, fadeOpacity = 0.5, loop = true, loopDelay = 1, }) => {
44
+ const idRef = useRef(null);
45
+ if (idRef.current === null) {
46
+ idRef.current = `txr${globalIdCounter++}`;
47
+ }
48
+ const uniqueId = idRef.current;
49
+ const finalParticleColor = particleColor || color;
50
+ const isFragmented = chaosMode === "fragmented";
51
+ // Loop via remount
52
+ const [cycle, setCycle] = useState(0);
53
+ // Layout the text into paths
54
+ const { paths: layoutPaths, width: textWidth, height: textHeight } = useMemo(() => {
55
+ return layoutText(text, { letterSpacing, scale });
56
+ }, [text, letterSpacing, scale]);
57
+ // Calculate centering offset
58
+ const offsetX = centerText ? (width - textWidth) / 2 : 0;
59
+ const offsetY = centerText ? (height - textHeight) / 2 : 0;
60
+ // Apply offset to paths
61
+ const resolvedPaths = useMemo(() => {
62
+ return layoutPaths.map((path) => (Object.assign(Object.assign({}, path), { d: offsetPath(path.d, offsetX, offsetY) })));
63
+ }, [layoutPaths, offsetX, offsetY]);
64
+ // Calculate path data
65
+ const pathData = useMemo(() => {
66
+ return resolvedPaths.map((p) => ({
67
+ length: estimatePathLength(p.d),
68
+ endpoints: getPathEndpoints(p.d),
69
+ }));
70
+ }, [resolvedPaths]);
71
+ // Generate offsets for fragmented mode
72
+ const fragmentOffsets = useMemo(() => {
73
+ const random = seededRandom(42);
74
+ return resolvedPaths.map(() => ({
75
+ x: (random() - 0.5) * 120,
76
+ y: (random() - 0.5) * 80,
77
+ }));
78
+ }, [resolvedPaths]);
79
+ // Timing calculations
80
+ const numPaths = resolvedPaths.length || 1;
81
+ const perItemDotsDuration = (dotsDuration * 0.5) / numPaths;
82
+ const perItemLinesDuration = (dotsDuration * 0.5) / numPaths;
83
+ const perItemAssemblyDuration = chaosDuration / numPaths;
84
+ const dotsPhaseEnd = dotsDuration * 0.5;
85
+ const linesPhaseEnd = dotsDuration;
86
+ const assemblyEndTime = isFragmented ? dotsDuration + chaosDuration : 0;
87
+ const flowBeginTime = assemblyEndTime + flowDelay;
88
+ // Total animation duration
89
+ const totalDuration = flowBeginTime + flowDuration;
90
+ // Remount-based loop
91
+ useEffect(() => {
92
+ if (!loop)
93
+ return;
94
+ const timeout = setTimeout(() => {
95
+ setCycle((c) => c + 1);
96
+ }, (totalDuration + loopDelay) * 1000);
97
+ return () => clearTimeout(timeout);
98
+ }, [loop, totalDuration, loopDelay, cycle]);
99
+ // Calculate viewBox to fit content
100
+ const viewBox = `0 0 ${width} ${height}`;
101
+ return (React.createElement("svg", { key: cycle, width: width, height: height, viewBox: viewBox, xmlns: "http://www.w3.org/2000/svg", style: { opacity } },
102
+ React.createElement("defs", null,
103
+ showGlow && (React.createElement("filter", { id: `glow-${uniqueId}`, x: "-50%", y: "-50%", width: "200%", height: "200%" },
104
+ React.createElement("feGaussianBlur", { stdDeviation: "2", result: "blur" }),
105
+ React.createElement("feMerge", null,
106
+ React.createElement("feMergeNode", { in: "blur" }),
107
+ React.createElement("feMergeNode", { in: "SourceGraphic" })))),
108
+ React.createElement("radialGradient", { id: `particleGradient-${uniqueId}`, cx: "50%", cy: "50%", r: "50%" },
109
+ React.createElement("stop", { offset: "0%", style: { stopColor: finalParticleColor, stopOpacity: 1 } }),
110
+ React.createElement("stop", { offset: "100%", style: { stopColor: finalParticleColor, stopOpacity: 0.3 } }))),
111
+ React.createElement("g", { className: "text-paths" }, resolvedPaths.map((path, index) => {
112
+ const offset = fragmentOffsets[index];
113
+ const { length: pathLength, endpoints } = pathData[index] || {
114
+ length: 100,
115
+ endpoints: { start: { x: 0, y: 0 }, end: { x: 0, y: 0 } },
116
+ };
117
+ const dotRadius = strokeWidth / 2;
118
+ return (React.createElement("g", { key: path.id, transform: isFragmented ? `translate(${offset.x}, ${offset.y})` : undefined },
119
+ isFragmented && (React.createElement(React.Fragment, null,
120
+ React.createElement("circle", { cx: endpoints.start.x, cy: endpoints.start.y, r: dotRadius, fill: color, opacity: "0" },
121
+ React.createElement("animate", { attributeName: "opacity", from: "0", to: "1", dur: "0.15s", begin: `${index * perItemDotsDuration}s`, fill: "freeze" }),
122
+ React.createElement("animate", { attributeName: "opacity", from: "1", to: "0", dur: "0.2s", begin: `${dotsPhaseEnd + (index + 1) * perItemLinesDuration}s`, fill: "freeze" })),
123
+ React.createElement("circle", { cx: endpoints.end.x, cy: endpoints.end.y, r: dotRadius, fill: color, opacity: "0" },
124
+ React.createElement("animate", { attributeName: "opacity", from: "0", to: "1", dur: "0.15s", begin: `${index * perItemDotsDuration}s`, fill: "freeze" }),
125
+ React.createElement("animate", { attributeName: "opacity", from: "1", to: "0", dur: "0.2s", begin: `${dotsPhaseEnd + (index + 1) * perItemLinesDuration}s`, fill: "freeze" })))),
126
+ React.createElement("path", { d: path.d, fill: "none", stroke: color, strokeWidth: strokeWidth, strokeLinecap: "round", strokeLinejoin: "round", opacity: isFragmented ? 0 : 1, strokeDasharray: isFragmented ? pathLength : undefined, strokeDashoffset: isFragmented ? pathLength : undefined },
127
+ isFragmented && (React.createElement(React.Fragment, null,
128
+ React.createElement("animate", { attributeName: "opacity", values: `0;1;1;${fadeAfterAssembly ? fadeOpacity : 1}`, keyTimes: "0;0.1;0.9;1", dur: `${perItemLinesDuration + chaosDuration}s`, begin: `${dotsPhaseEnd + index * perItemLinesDuration}s`, fill: "freeze" }),
129
+ React.createElement("animate", { attributeName: "stroke-dashoffset", from: pathLength, to: "0", dur: `${perItemLinesDuration}s`, begin: `${dotsPhaseEnd + index * perItemLinesDuration}s`, fill: "freeze", calcMode: "spline", keySplines: "0.4 0 0.2 1", keyTimes: "0;1" }))),
130
+ !isFragmented && fadeAfterAssembly && (React.createElement("animate", { attributeName: "opacity", from: "1", to: fadeOpacity, dur: "0.5s", begin: `${flowBeginTime}s`, fill: "freeze" }))),
131
+ isFragmented && (React.createElement("animateTransform", { attributeName: "transform", type: "translate", from: `${offset.x} ${offset.y}`, to: "0 0", dur: `${perItemAssemblyDuration}s`, begin: `${linesPhaseEnd + index * perItemAssemblyDuration}s`, fill: "freeze", calcMode: "spline", keySplines: "0.33 0 0.2 1", keyTimes: "0;1" }))));
132
+ })),
133
+ React.createElement("g", { className: "text-particles", filter: showGlow ? `url(#glow-${uniqueId})` : undefined }, resolvedPaths.flatMap((path, pathIndex) => {
134
+ return Array.from({ length: particlesPerPath }).map((_, particleIndex) => {
135
+ const particleDelay = (particleIndex / particlesPerPath) * flowDuration;
136
+ const beginTime = flowBeginTime + particleDelay;
137
+ return (React.createElement("circle", { key: `particle-${pathIndex}-${particleIndex}`, r: particleRadius, fill: `url(#particleGradient-${uniqueId})`, opacity: "0" },
138
+ React.createElement("animateMotion", { dur: `${flowDuration}s`, begin: `${beginTime}s`, fill: "freeze", path: path.d }),
139
+ React.createElement("animate", { attributeName: "opacity", values: "0;1;1;0", keyTimes: "0;0.1;0.9;1", dur: `${flowDuration}s`, begin: `${beginTime}s`, fill: "freeze" })));
140
+ });
141
+ }))));
142
+ };
143
+ /**
144
+ * Offset all coordinates in a path by the given amounts
145
+ */
146
+ function offsetPath(d, offsetX, offsetY) {
147
+ let coordIndex = 0;
148
+ return d.replace(/-?\d+\.?\d*/g, (match) => {
149
+ const num = parseFloat(match);
150
+ const isY = coordIndex % 2 === 1;
151
+ coordIndex++;
152
+ if (isY) {
153
+ return String(num + offsetY);
154
+ }
155
+ else {
156
+ return String(num + offsetX);
157
+ }
158
+ });
159
+ }
@@ -0,0 +1,85 @@
1
+ import React from 'react';
2
+ export const WreathLogo = ({ width = 150, height = 150, pColor = '#2C3E50', wreathColor = '#27AE60', leafAccentColor = '#52BE80', opacity = 0.9, animationSpeed = 3, }) => {
3
+ const wreathRadius = 58;
4
+ return (React.createElement("svg", { width: width, height: height, viewBox: "0 0 200 200", xmlns: "http://www.w3.org/2000/svg", style: { opacity } },
5
+ React.createElement("defs", null,
6
+ React.createElement("radialGradient", { id: "wreathGlow", cx: "50%", cy: "50%", r: "50%" },
7
+ React.createElement("stop", { offset: "0%", style: { stopColor: wreathColor, stopOpacity: 0.3 } }),
8
+ React.createElement("stop", { offset: "100%", style: { stopColor: wreathColor, stopOpacity: 0 } })),
9
+ React.createElement("filter", { id: "softGlow" },
10
+ React.createElement("feGaussianBlur", { stdDeviation: "2", result: "coloredBlur" }),
11
+ React.createElement("feMerge", null,
12
+ React.createElement("feMergeNode", { in: "coloredBlur" }),
13
+ React.createElement("feMergeNode", { in: "SourceGraphic" })))),
14
+ React.createElement("circle", { cx: "100", cy: "100", r: "70", fill: "url(#wreathGlow)", opacity: "0.3" }),
15
+ React.createElement("path", { d: (() => {
16
+ const numPoints = 24;
17
+ const waveAmplitude = 2;
18
+ let pathD = '';
19
+ const points = [];
20
+ // Generate all points first
21
+ for (let i = 0; i <= numPoints; i++) {
22
+ const angle = (360 / numPoints) * i;
23
+ const radians = (angle * Math.PI) / 180;
24
+ // Use sine wave for smooth variation
25
+ const radiusVariation = Math.sin((angle * Math.PI) / 180 * 6) * waveAmplitude;
26
+ const currentRadius = wreathRadius + radiusVariation;
27
+ const x = 100 + currentRadius * Math.cos(radians);
28
+ const y = 100 + currentRadius * Math.sin(radians);
29
+ points.push({ x, y, angle, radians });
30
+ }
31
+ // Create smooth cubic bezier path with better control points
32
+ pathD = `M ${points[0].x},${points[0].y}`;
33
+ for (let i = 0; i < points.length - 1; i++) {
34
+ const current = points[i];
35
+ const next = points[i + 1];
36
+ // Calculate tangent for smooth curves
37
+ const tangentLength = 0.4;
38
+ const cp1x = current.x - Math.sin(current.radians) * tangentLength * 15;
39
+ const cp1y = current.y + Math.cos(current.radians) * tangentLength * 15;
40
+ const cp2x = next.x + Math.sin(next.radians) * tangentLength * 15;
41
+ const cp2y = next.y - Math.cos(next.radians) * tangentLength * 15;
42
+ pathD += ` C ${cp1x},${cp1y} ${cp2x},${cp2y} ${next.x},${next.y}`;
43
+ }
44
+ return pathD + ' Z';
45
+ })(), fill: "none", stroke: wreathColor, strokeWidth: "7", strokeLinecap: "round", strokeLinejoin: "round", opacity: "0.75", filter: "url(#softGlow)" },
46
+ React.createElement("animate", { attributeName: "stroke-opacity", values: "0.65;0.85;0.65", dur: `${animationSpeed}s`, repeatCount: "indefinite" })),
47
+ React.createElement("path", { d: (() => {
48
+ const numPoints = 24;
49
+ const waveAmplitude = 1.5;
50
+ const innerRadius = wreathRadius - 9;
51
+ let pathD = '';
52
+ const points = [];
53
+ for (let i = 0; i <= numPoints; i++) {
54
+ const angle = (360 / numPoints) * i + 15; // Offset from main wreath
55
+ const radians = (angle * Math.PI) / 180;
56
+ // Use sine wave offset for smooth variation
57
+ const radiusVariation = Math.sin(((angle + 30) * Math.PI) / 180 * 6) * waveAmplitude;
58
+ const currentRadius = innerRadius + radiusVariation;
59
+ const x = 100 + currentRadius * Math.cos(radians);
60
+ const y = 100 + currentRadius * Math.sin(radians);
61
+ points.push({ x, y, radians });
62
+ }
63
+ pathD = `M ${points[0].x},${points[0].y}`;
64
+ for (let i = 0; i < points.length - 1; i++) {
65
+ const current = points[i];
66
+ const next = points[i + 1];
67
+ const tangentLength = 0.4;
68
+ const cp1x = current.x - Math.sin(current.radians) * tangentLength * 15;
69
+ const cp1y = current.y + Math.cos(current.radians) * tangentLength * 15;
70
+ const cp2x = next.x + Math.sin(next.radians) * tangentLength * 15;
71
+ const cp2y = next.y - Math.cos(next.radians) * tangentLength * 15;
72
+ pathD += ` C ${cp1x},${cp1y} ${cp2x},${cp2y} ${next.x},${next.y}`;
73
+ }
74
+ return pathD + ' Z';
75
+ })(), fill: "none", stroke: leafAccentColor, strokeWidth: "5", strokeLinecap: "round", strokeLinejoin: "round", opacity: "0.6", filter: "url(#softGlow)" },
76
+ React.createElement("animate", { attributeName: "stroke-opacity", values: "0.5;0.7;0.5", dur: `${animationSpeed}s`, repeatCount: "indefinite", begin: "0.5s" })),
77
+ React.createElement("g", { filter: "url(#softGlow)" },
78
+ React.createElement("defs", null,
79
+ React.createElement("linearGradient", { id: "pGradient", x1: "0%", y1: "0%", x2: "0%", y2: "100%" },
80
+ React.createElement("stop", { offset: "0%", style: { stopColor: pColor, stopOpacity: 1 } }),
81
+ React.createElement("stop", { offset: "100%", style: { stopColor: pColor, stopOpacity: 0.85 } }))),
82
+ React.createElement("path", { d: "M 82,70\n L 82,130\n L 90,130\n L 90,102\n L 104,102\n C 114,102 122,94 122,84\n C 122,74 114,70 104,70\n Z\n M 90,78\n L 104,78\n C 109,78 114,80 114,84\n C 114,88 109,94 104,94\n L 90,94\n Z", fill: "url(#pGradient)" },
83
+ React.createElement("animate", { attributeName: "opacity", values: "0.95;1;0.95", dur: `${animationSpeed}s`, repeatCount: "indefinite" })),
84
+ React.createElement("path", { d: "M 83,72 L 83,128 L 84,128 L 84,72 Z", fill: "white", opacity: "0.15" }))));
85
+ };
package/dist/esm/index.js CHANGED
@@ -1,3 +1,10 @@
1
1
  export { Logo } from './Logo';
2
2
  export { LogoSmall } from './LogoSmall';
3
3
  export { ForksLogo } from './ForksLogo';
4
+ export { SquareLogo } from './SquareLogo';
5
+ export { WreathLogo } from './WreathLogo';
6
+ export { TelemetryReveal } from './TelemetryReveal';
7
+ export { TextReveal } from './TextReveal';
8
+ export { OpenTypeTextReveal } from './OpenTypeTextReveal';
9
+ export { TELEMETRY_PRESETS } from './presets';
10
+ export { STROKE_CHARACTERS, layoutText } from './strokeCharacters';
@@ -0,0 +1,88 @@
1
+ export const TELEMETRY_PRESETS = {
2
+ network: {
3
+ name: "network",
4
+ viewBox: "0 0 200 200",
5
+ paths: [
6
+ // Cardinal directions
7
+ { d: "M 100,100 L 100,30", id: "n-top" },
8
+ { d: "M 100,100 L 170,100", id: "n-right" },
9
+ { d: "M 100,100 L 100,170", id: "n-bottom" },
10
+ { d: "M 100,100 L 30,100", id: "n-left" },
11
+ // Diagonals
12
+ { d: "M 100,100 L 150,50", id: "n-tr" },
13
+ { d: "M 100,100 L 150,150", id: "n-br" },
14
+ { d: "M 100,100 L 50,150", id: "n-bl" },
15
+ { d: "M 100,100 L 50,50", id: "n-tl" },
16
+ ],
17
+ },
18
+ tree: {
19
+ name: "tree",
20
+ viewBox: "0 0 200 200",
21
+ paths: [
22
+ // Root to trunk
23
+ { d: "M 100,180 L 100,100", id: "trunk" },
24
+ // Main branches
25
+ { d: "M 100,100 L 55,55", id: "branch-l1" },
26
+ { d: "M 100,100 L 145,55", id: "branch-r1" },
27
+ // Sub-branches left
28
+ { d: "M 55,55 L 30,25", id: "branch-l2" },
29
+ { d: "M 55,55 L 70,25", id: "branch-l3" },
30
+ // Sub-branches right
31
+ { d: "M 145,55 L 130,25", id: "branch-r2" },
32
+ { d: "M 145,55 L 170,25", id: "branch-r3" },
33
+ ],
34
+ },
35
+ circuit: {
36
+ name: "circuit",
37
+ viewBox: "0 0 200 200",
38
+ paths: [
39
+ // Horizontal bus lines
40
+ { d: "M 25,50 L 175,50", id: "h1" },
41
+ { d: "M 25,100 L 175,100", id: "h2" },
42
+ { d: "M 25,150 L 175,150", id: "h3" },
43
+ // Vertical connectors
44
+ { d: "M 60,50 L 60,100", id: "v1" },
45
+ { d: "M 100,50 L 100,150", id: "v2" },
46
+ { d: "M 140,100 L 140,150", id: "v3" },
47
+ ],
48
+ },
49
+ hexagon: {
50
+ name: "hexagon",
51
+ viewBox: "0 0 200 200",
52
+ paths: [
53
+ // Hexagon edges (clockwise from top)
54
+ { d: "M 100,25 L 160,55", id: "hex1" },
55
+ { d: "M 160,55 L 160,125", id: "hex2" },
56
+ { d: "M 160,125 L 100,155", id: "hex3" },
57
+ { d: "M 100,155 L 40,125", id: "hex4" },
58
+ { d: "M 40,125 L 40,55", id: "hex5" },
59
+ { d: "M 40,55 L 100,25", id: "hex6" },
60
+ // Spokes to center
61
+ { d: "M 100,90 L 100,25", id: "spoke1" },
62
+ { d: "M 100,90 L 160,55", id: "spoke2" },
63
+ { d: "M 100,90 L 160,125", id: "spoke3" },
64
+ ],
65
+ },
66
+ codebase: {
67
+ name: "codebase",
68
+ viewBox: "0 0 200 200",
69
+ paths: [
70
+ // Root vertical line
71
+ { d: "M 35,35 L 35,165", id: "root" },
72
+ // First level directories
73
+ { d: "M 35,55 L 75,55", id: "dir1" },
74
+ { d: "M 35,90 L 75,90", id: "dir2" },
75
+ { d: "M 35,125 L 75,125", id: "dir3" },
76
+ // Nested structure from dir1
77
+ { d: "M 75,55 L 75,80", id: "sub1" },
78
+ { d: "M 75,65 L 115,65", id: "file1" },
79
+ // Nested structure from dir2
80
+ { d: "M 75,90 L 75,115", id: "sub2" },
81
+ { d: "M 75,100 L 135,100", id: "file2" },
82
+ { d: "M 75,110 L 105,110", id: "file3" },
83
+ // Cross-references (dependencies)
84
+ { d: "M 115,65 L 155,45", id: "link1" },
85
+ { d: "M 135,100 L 165,80", id: "link2" },
86
+ ],
87
+ },
88
+ };