@principal-ai/logo-component 0.1.4 → 0.1.5

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,339 @@
1
+ import React, { useMemo, useState, useEffect } from "react";
2
+ import { MazeGenerator } from "./utils/mazeGenerator";
3
+ export const MazeDemo = ({ width = 450, height = 620, mazeColor = "#6366f1", errorColor = "#ef4444", searchColor = "#f59e0b", solutionColor = "#10b981", mazeSeed = 42, }) => {
4
+ // Maze configuration
5
+ const gridSize = 10;
6
+ const cellSize = 30;
7
+ const padding = 50;
8
+ const mazeWidth = gridSize * cellSize;
9
+ const mazeHeight = gridSize * cellSize;
10
+ const mazeX = (width - mazeWidth) / 2;
11
+ // Key positions
12
+ const startCol = 0;
13
+ const startRow = 0;
14
+ const destCol = 9;
15
+ const destRow = 9;
16
+ // State
17
+ const [revealedCells, setRevealedCells] = useState([]);
18
+ const [directionHint, setDirectionHint] = useState("");
19
+ const [timeCost, setTimeCost] = useState(0);
20
+ const [clickCost, setClickCost] = useState(0);
21
+ const [blockageFound, setBlockageFound] = useState(false);
22
+ const [startTime, setStartTime] = useState(null);
23
+ const [started, setStarted] = useState(false);
24
+ const [currentSeed, setCurrentSeed] = useState(() => Math.floor(Math.random() * 10000));
25
+ const [blockageInjected, setBlockageInjected] = useState(false);
26
+ const [deployed, setDeployed] = useState(false);
27
+ const [mode, setMode] = useState('initial');
28
+ // Total incident cost
29
+ const incidentCost = timeCost + clickCost;
30
+ // Update currentSeed when mazeSeed prop changes
31
+ useEffect(() => {
32
+ setCurrentSeed(mazeSeed);
33
+ }, [mazeSeed]);
34
+ // Increment time cost
35
+ useEffect(() => {
36
+ if (blockageFound || !startTime || !started)
37
+ return;
38
+ const interval = setInterval(() => {
39
+ setTimeCost(prev => prev + 1);
40
+ }, 10);
41
+ return () => clearInterval(interval);
42
+ }, [blockageFound, startTime, started]);
43
+ // Generate maze
44
+ const { horizontalWalls, verticalWalls, blockageWall, actualBlockageCol, actualBlockageRow } = useMemo(() => {
45
+ let seed = currentSeed;
46
+ const seededRandom = () => {
47
+ seed = (seed * 9301 + 49297) % 233280;
48
+ return seed / 233280;
49
+ };
50
+ const originalRandom = Math.random;
51
+ Math.random = seededRandom;
52
+ const generator = new MazeGenerator(gridSize, gridSize);
53
+ generator.generate(startRow, startCol);
54
+ let blockCell = { row: 5, col: 5 };
55
+ let direction = 'east';
56
+ let blockageWall = null;
57
+ if (blockageInjected) {
58
+ const path = generator.findPath(startRow, startCol, destRow, destCol);
59
+ if (path.length > 2) {
60
+ const middleStart = Math.floor(path.length * 0.3);
61
+ const middleEnd = Math.floor(path.length * 0.7);
62
+ const blockIndex = Math.floor(seededRandom() * (middleEnd - middleStart)) + middleStart;
63
+ blockCell = path[blockIndex];
64
+ if (blockIndex < path.length - 1) {
65
+ const nextCell = path[blockIndex + 1];
66
+ const rowDiff = nextCell.row - blockCell.row;
67
+ const colDiff = nextCell.col - blockCell.col;
68
+ if (rowDiff === 1)
69
+ direction = 'south';
70
+ else if (rowDiff === -1)
71
+ direction = 'north';
72
+ else if (colDiff === 1)
73
+ direction = 'east';
74
+ else if (colDiff === -1)
75
+ direction = 'west';
76
+ }
77
+ }
78
+ generator.addBlockage(blockCell.row, blockCell.col, direction);
79
+ }
80
+ const walls = generator.getWalls();
81
+ if (blockageInjected) {
82
+ if (direction === 'east' || direction === 'west') {
83
+ const targetCol = direction === 'east' ? blockCell.col + 1 : blockCell.col;
84
+ const targetRow = blockCell.row;
85
+ const wallSegment = walls.vertical.find(wall => {
86
+ const [col, row1, , row2] = wall;
87
+ return col === targetCol && row1 <= targetRow && row2 > targetRow;
88
+ });
89
+ if (wallSegment) {
90
+ const [col, row1, , row2] = wallSegment;
91
+ blockageWall = { type: 'vertical', col, row1, row2 };
92
+ }
93
+ }
94
+ else {
95
+ const targetRow = direction === 'south' ? blockCell.row + 1 : blockCell.row;
96
+ const targetCol = blockCell.col;
97
+ const wallSegment = walls.horizontal.find(wall => {
98
+ const [col1, row, col2] = wall;
99
+ return row === targetRow && col1 <= targetCol && col2 > targetCol;
100
+ });
101
+ if (wallSegment) {
102
+ const [col1, row, col2] = wallSegment;
103
+ blockageWall = { type: 'horizontal', row, col1, col2 };
104
+ }
105
+ }
106
+ }
107
+ Math.random = originalRandom;
108
+ return {
109
+ horizontalWalls: walls.horizontal,
110
+ verticalWalls: walls.vertical,
111
+ blockageWall,
112
+ actualBlockageCol: blockCell.col,
113
+ actualBlockageRow: blockCell.row,
114
+ };
115
+ }, [currentSeed, blockageInjected]);
116
+ // Handlers
117
+ const handleModeSelect = (selectedMode) => {
118
+ setMode(selectedMode);
119
+ };
120
+ const handleDeploy = () => {
121
+ setDeployed(true);
122
+ setTimeout(() => {
123
+ setBlockageInjected(true);
124
+ setStarted(true);
125
+ setStartTime(Date.now());
126
+ }, 3000);
127
+ };
128
+ const handleTryPrincipal = () => {
129
+ setMode('principal');
130
+ setRevealedCells([]);
131
+ setDirectionHint("");
132
+ setBlockageFound(false);
133
+ setTimeCost(0);
134
+ setClickCost(0);
135
+ setStartTime(null);
136
+ setStarted(false);
137
+ setDeployed(false);
138
+ setBlockageInjected(false); // Principal mode still needs to deploy first
139
+ };
140
+ const handleTryAgain = () => {
141
+ setRevealedCells([]);
142
+ setDirectionHint("");
143
+ setBlockageFound(false);
144
+ setTimeCost(0);
145
+ setClickCost(0);
146
+ setStartTime(null);
147
+ setStarted(false);
148
+ setBlockageInjected(false);
149
+ setDeployed(false);
150
+ setMode('initial');
151
+ setCurrentSeed(Math.floor(Math.random() * 10000));
152
+ };
153
+ const handleCellClick = (col, row) => {
154
+ if (blockageFound || !started)
155
+ return;
156
+ // In principal mode, only allow clicking the blockage cell
157
+ if (mode === 'principal') {
158
+ const isBlockageCell = col === actualBlockageCol && row === actualBlockageRow;
159
+ if (isBlockageCell) {
160
+ setDirectionHint("🎯 Blockage Found!");
161
+ setBlockageFound(true);
162
+ }
163
+ return;
164
+ }
165
+ const alreadyRevealed = revealedCells.some(cell => cell.col === col && cell.row === row);
166
+ if (alreadyRevealed)
167
+ return;
168
+ setClickCost(prev => prev + 500);
169
+ setRevealedCells([...revealedCells, { col, row }]);
170
+ const isBlockageCell = col === actualBlockageCol && row === actualBlockageRow;
171
+ if (isBlockageCell) {
172
+ setDirectionHint("🎯 Blockage Found!");
173
+ setBlockageFound(true);
174
+ const cellsToReveal = [...revealedCells];
175
+ for (let r = 0; r < gridSize; r++) {
176
+ for (let c = 0; c < gridSize; c++) {
177
+ const distance = Math.abs(actualBlockageCol - c) + Math.abs(actualBlockageRow - r);
178
+ if (distance <= 3) {
179
+ const alreadyInList = cellsToReveal.some(cell => cell.col === c && cell.row === r);
180
+ if (!alreadyInList) {
181
+ cellsToReveal.push({ col: c, row: r });
182
+ }
183
+ }
184
+ }
185
+ }
186
+ setRevealedCells(cellsToReveal);
187
+ }
188
+ else {
189
+ const colDiff = actualBlockageCol - col;
190
+ const rowDiff = actualBlockageRow - row;
191
+ let direction = "";
192
+ if (Math.abs(rowDiff) > 1) {
193
+ direction += rowDiff > 0 ? "↓ " : "↑ ";
194
+ }
195
+ if (Math.abs(colDiff) > 1) {
196
+ direction += colDiff > 0 ? "→" : "←";
197
+ }
198
+ const distance = Math.abs(colDiff) + Math.abs(rowDiff);
199
+ let proximity = "";
200
+ if (distance <= 2)
201
+ proximity = "Very close!";
202
+ else if (distance <= 4)
203
+ proximity = "Getting warmer...";
204
+ else if (distance <= 6)
205
+ proximity = "Still far...";
206
+ else
207
+ proximity = "Cold...";
208
+ setDirectionHint(`${direction} ${proximity}`);
209
+ }
210
+ };
211
+ // Render maze
212
+ const renderMaze = (showBlockage, opacity = 1) => {
213
+ const elements = [];
214
+ elements.push(React.createElement("rect", { key: "background", x: mazeX, y: padding, width: mazeWidth, height: mazeHeight, fill: "none", stroke: mazeColor, strokeWidth: "3", opacity: 0.3 * opacity }));
215
+ const isBlockageWall = (type, wall) => {
216
+ if (!showBlockage || !blockageWall)
217
+ return false;
218
+ if (type === 'vertical') {
219
+ const [x, y1, , y2] = wall;
220
+ return (blockageWall.type === 'vertical' &&
221
+ x === blockageWall.col &&
222
+ y1 === blockageWall.row1 &&
223
+ y2 === blockageWall.row2);
224
+ }
225
+ else if (type === 'horizontal') {
226
+ const [x1, y, x2] = wall;
227
+ return (blockageWall.type === 'horizontal' &&
228
+ y === blockageWall.row &&
229
+ x1 === blockageWall.col1 &&
230
+ x2 === blockageWall.col2);
231
+ }
232
+ return false;
233
+ };
234
+ horizontalWalls.forEach((wall, idx) => {
235
+ const [x1, y, x2] = wall;
236
+ const isBlockage = isBlockageWall('horizontal', wall);
237
+ elements.push(React.createElement("line", { key: `h-wall-${idx}`, x1: mazeX + x1 * cellSize, y1: padding + y * cellSize, x2: mazeX + x2 * cellSize, y2: padding + y * cellSize, stroke: isBlockage ? errorColor : mazeColor, strokeWidth: isBlockage ? 4 : 2.5, strokeLinecap: "round", opacity: opacity }, isBlockage && showBlockage && (React.createElement("animate", { attributeName: "stroke-width", values: "4;6;4", dur: "1.5s", repeatCount: "indefinite" }))));
238
+ });
239
+ verticalWalls.forEach((wall, idx) => {
240
+ const [x, y1, , y2] = wall;
241
+ const isBlockage = isBlockageWall('vertical', wall);
242
+ elements.push(React.createElement("line", { key: `v-wall-${idx}`, x1: mazeX + x * cellSize, y1: padding + y1 * cellSize, x2: mazeX + x * cellSize, y2: padding + y2 * cellSize, stroke: isBlockage ? errorColor : mazeColor, strokeWidth: isBlockage ? 4 : 2.5, strokeLinecap: "round", opacity: opacity }, isBlockage && showBlockage && (React.createElement("animate", { attributeName: "stroke-width", values: "4;6;4", dur: "1.5s", repeatCount: "indefinite" }))));
243
+ });
244
+ for (let row = 0; row <= gridSize; row++) {
245
+ elements.push(React.createElement("line", { key: `grid-h-${row}`, x1: mazeX, y1: padding + row * cellSize, x2: mazeX + mazeWidth, y2: padding + row * cellSize, stroke: mazeColor, strokeWidth: "0.5", opacity: 0.15 * opacity }));
246
+ }
247
+ for (let col = 0; col <= gridSize; col++) {
248
+ elements.push(React.createElement("line", { key: `grid-v-${col}`, x1: mazeX + col * cellSize, y1: padding, x2: mazeX + col * cellSize, y2: padding + mazeHeight, stroke: mazeColor, strokeWidth: "0.5", opacity: 0.15 * opacity }));
249
+ }
250
+ return elements;
251
+ };
252
+ const getTitle = () => {
253
+ if (mode === 'principal')
254
+ return "With Principal";
255
+ if (mode === 'agentic')
256
+ return "With Agentic Coding";
257
+ if (mode === 'no-agentic')
258
+ return "Without Agentic Coding";
259
+ return "Choose Your Approach";
260
+ };
261
+ const getSubtitle = () => {
262
+ if (mode === 'principal')
263
+ return "Full visibility - See everything";
264
+ if (started)
265
+ return "Find the blockage";
266
+ if (deployed)
267
+ return "Running smoothly...";
268
+ return "How will you handle production?";
269
+ };
270
+ const showCover = mode === 'agentic' || (deployed && mode === 'no-agentic');
271
+ const coverOpacity = 1; // Always full opacity for the cover
272
+ const mazeOpacity = 1; // Maze always at full opacity, cover handles visibility
273
+ return (React.createElement("svg", { width: width, height: height, xmlns: "http://www.w3.org/2000/svg" },
274
+ React.createElement("text", { x: width / 2, y: 25, textAnchor: "middle", fill: mazeColor, fontSize: "16", fontWeight: "bold" }, getTitle()),
275
+ React.createElement("text", { x: width / 2, y: 40, textAnchor: "middle", fill: mazeColor, fontSize: "11", opacity: "0.6" }, getSubtitle()),
276
+ mode !== 'initial' && (React.createElement(React.Fragment, null,
277
+ React.createElement("g", null, renderMaze(mode === 'principal' || blockageFound, mazeOpacity)),
278
+ React.createElement("circle", { cx: mazeX + (startCol + 0.5) * cellSize, cy: padding + (startRow + 0.5) * cellSize, r: "5", fill: searchColor }),
279
+ React.createElement("text", { x: mazeX - 5, y: padding - 5, textAnchor: "end", fontSize: "10", fill: searchColor, fontWeight: "bold" }, "START"),
280
+ React.createElement("g", null,
281
+ React.createElement("circle", { cx: mazeX + (destCol + 0.5) * cellSize, cy: padding + (destRow + 0.5) * cellSize, r: "8", fill: "none", stroke: mazeColor, strokeWidth: "1.5", opacity: "0.5" }),
282
+ React.createElement("circle", { cx: mazeX + (destCol + 0.5) * cellSize, cy: padding + (destRow + 0.5) * cellSize, r: "5", fill: "none", stroke: mazeColor, strokeWidth: "1.5", opacity: "0.6" }),
283
+ React.createElement("circle", { cx: mazeX + (destCol + 0.5) * cellSize, cy: padding + (destRow + 0.5) * cellSize, r: "2", fill: mazeColor, opacity: "0.7" })),
284
+ React.createElement("text", { x: mazeX + mazeWidth + 5, y: padding + mazeHeight + 15, textAnchor: "start", fontSize: "9", fill: mazeColor, fontWeight: "bold" }, "DEST"))),
285
+ showCover && (React.createElement(React.Fragment, null,
286
+ React.createElement("defs", null,
287
+ React.createElement("mask", { id: "mazeCoverMask" },
288
+ React.createElement("rect", { x: mazeX, y: padding, width: mazeWidth, height: mazeHeight, fill: "white" }),
289
+ revealedCells.map((cell, idx) => (React.createElement("rect", { key: idx, x: mazeX + cell.col * cellSize, y: padding + cell.row * cellSize, width: cellSize, height: cellSize, fill: "black" }))))),
290
+ React.createElement("g", null,
291
+ React.createElement("rect", { x: mazeX, y: padding, width: mazeWidth, height: mazeHeight, fill: "#2a2a2a", opacity: coverOpacity, mask: "url(#mazeCoverMask)" }),
292
+ React.createElement("rect", { x: mazeX, y: padding, width: mazeWidth, height: mazeHeight, fill: "none", stroke: mazeColor, strokeWidth: "3", opacity: "0.4" }),
293
+ started && revealedCells.length === 0 && (React.createElement("g", null,
294
+ React.createElement("rect", { x: mazeX + mazeWidth / 2 - 130, y: padding + mazeHeight / 2 - 40, width: 260, height: 80, fill: "#000000", opacity: "0.7", rx: "8", pointerEvents: "none" }),
295
+ React.createElement("text", { x: mazeX + mazeWidth / 2, y: padding + mazeHeight / 2 - 15, textAnchor: "middle", fontSize: "18", fill: errorColor, fontWeight: "bold", pointerEvents: "none" }, "\uD83D\uDEA8 INCIDENT ALERT"),
296
+ React.createElement("text", { x: mazeX + mazeWidth / 2, y: padding + mazeHeight / 2 + 10, textAnchor: "middle", fontSize: "13", fill: "#ffffff", fontWeight: "normal", pointerEvents: "none" }, "It's 3:00 AM - Find the blockage!"))),
297
+ started && revealedCells.length > 0 && directionHint && (React.createElement("g", null,
298
+ React.createElement("rect", { x: mazeX + mazeWidth / 2 - 100, y: padding + mazeHeight / 2 - 25, width: 200, height: 40, fill: "#000000", opacity: "0.7", rx: "6", pointerEvents: "none" }),
299
+ React.createElement("text", { x: mazeX + mazeWidth / 2, y: padding + mazeHeight / 2, textAnchor: "middle", fontSize: "16", fill: "#ffffff", fontWeight: "bold", pointerEvents: "none" }, directionHint)))))),
300
+ started && (React.createElement("g", null, Array.from({ length: gridSize }).map((_, row) => Array.from({ length: gridSize }).map((_, col) => (React.createElement("rect", { key: `cell-${row}-${col}`, x: mazeX + col * cellSize, y: padding + row * cellSize, width: cellSize, height: cellSize, fill: "transparent", stroke: "none", style: { cursor: 'pointer' }, onClick: () => handleCellClick(col, row), onMouseEnter: (e) => {
301
+ e.currentTarget.setAttribute('fill', searchColor);
302
+ e.currentTarget.setAttribute('opacity', '0.1');
303
+ }, onMouseLeave: (e) => {
304
+ e.currentTarget.setAttribute('fill', 'transparent');
305
+ e.currentTarget.setAttribute('opacity', '1');
306
+ } })))))),
307
+ mode === 'initial' && (React.createElement("g", null,
308
+ React.createElement("g", { style: { cursor: 'pointer' }, onClick: () => handleModeSelect('no-agentic') },
309
+ React.createElement("rect", { x: mazeX + mazeWidth / 2 - 130, y: padding + mazeHeight + 25, width: 120, height: 40, fill: searchColor, rx: "6" }),
310
+ React.createElement("text", { x: mazeX + mazeWidth / 2 - 70, y: padding + mazeHeight + 52, textAnchor: "middle", fontSize: "12", fill: "#ffffff", fontWeight: "bold", pointerEvents: "none" }, "No Agentic")),
311
+ React.createElement("g", { style: { cursor: 'pointer' }, onClick: () => handleModeSelect('agentic') },
312
+ React.createElement("rect", { x: mazeX + mazeWidth / 2 + 10, y: padding + mazeHeight + 25, width: 120, height: 40, fill: mazeColor, rx: "6" }),
313
+ React.createElement("text", { x: mazeX + mazeWidth / 2 + 70, y: padding + mazeHeight + 52, textAnchor: "middle", fontSize: "12", fill: "#ffffff", fontWeight: "bold", pointerEvents: "none" }, "Agentic Coding")))),
314
+ (mode === 'no-agentic' || mode === 'agentic' || mode === 'principal') && !deployed && (React.createElement("g", null,
315
+ React.createElement("g", { style: { cursor: 'pointer' }, onClick: handleDeploy },
316
+ React.createElement("rect", { x: mazeX + mazeWidth / 2 - 60, y: padding + mazeHeight + 25, width: 120, height: 40, fill: searchColor, rx: "6" }),
317
+ React.createElement("text", { x: mazeX + mazeWidth / 2, y: padding + mazeHeight + 52, textAnchor: "middle", fontSize: "16", fill: "#ffffff", fontWeight: "bold", pointerEvents: "none" }, "DEPLOY")))),
318
+ deployed && !started && (React.createElement("g", null,
319
+ React.createElement("rect", { x: mazeX, y: padding + mazeHeight + 20, width: mazeWidth, height: 35, fill: solutionColor, opacity: "0.9", rx: "4" }),
320
+ React.createElement("text", { x: mazeX + mazeWidth / 2, y: padding + mazeHeight + 35, textAnchor: "middle", fontSize: "11", fill: "#ffffff", fontWeight: "normal" }, "\u2713 Deployment Successful"),
321
+ React.createElement("text", { x: mazeX + mazeWidth / 2, y: padding + mazeHeight + 50, textAnchor: "middle", fontSize: "14", fill: "#ffffff", fontWeight: "bold" }, "All systems operational"))),
322
+ started && (React.createElement("g", null,
323
+ React.createElement("rect", { x: mazeX, y: padding + mazeHeight + 20, width: mazeWidth, height: 35, fill: blockageFound ? solutionColor : errorColor, opacity: "0.9", rx: "4" }),
324
+ React.createElement("text", { x: mazeX + mazeWidth / 2, y: padding + mazeHeight + 35, textAnchor: "middle", fontSize: "11", fill: "#ffffff", fontWeight: "normal" }, blockageFound ? "Incident Resolved!" : "Incident Cost"),
325
+ React.createElement("text", { x: mazeX + mazeWidth / 2, y: padding + mazeHeight + 50, textAnchor: "middle", fontSize: "18", fill: "#ffffff", fontWeight: "bold" },
326
+ "$",
327
+ incidentCost.toLocaleString()))),
328
+ started && blockageFound && mode !== 'principal' && (React.createElement("g", null,
329
+ React.createElement("g", { style: { cursor: 'pointer' }, onClick: handleTryAgain },
330
+ React.createElement("rect", { x: mazeX + mazeWidth / 2 - 130, y: padding + mazeHeight + 65, width: 120, height: 25, fill: mazeColor, opacity: "0.2", rx: "4" }),
331
+ React.createElement("text", { x: mazeX + mazeWidth / 2 - 70, y: padding + mazeHeight + 82, textAnchor: "middle", fontSize: "10", fill: mazeColor, fontWeight: "bold", pointerEvents: "none" }, "Try Again")),
332
+ React.createElement("g", { style: { cursor: 'pointer' }, onClick: handleTryPrincipal },
333
+ React.createElement("rect", { x: mazeX + mazeWidth / 2 + 10, y: padding + mazeHeight + 65, width: 120, height: 25, fill: solutionColor, opacity: "0.8", rx: "4" }),
334
+ React.createElement("text", { x: mazeX + mazeWidth / 2 + 70, y: padding + mazeHeight + 82, textAnchor: "middle", fontSize: "10", fill: "#ffffff", fontWeight: "bold", pointerEvents: "none" }, "Try with Principal")))),
335
+ mode === 'principal' && blockageFound && (React.createElement("g", null,
336
+ React.createElement("g", { style: { cursor: 'pointer' }, onClick: handleTryAgain },
337
+ React.createElement("rect", { x: mazeX + mazeWidth / 2 - 60, y: padding + mazeHeight + 65, width: 120, height: 25, fill: mazeColor, opacity: "0.3", rx: "4" }),
338
+ React.createElement("text", { x: mazeX + mazeWidth / 2, y: padding + mazeHeight + 82, textAnchor: "middle", fontSize: "10", fill: mazeColor, fontWeight: "bold", pointerEvents: "none" }, "Try Again"))))));
339
+ };