bits-lab 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +51 -2
- package/dist/Accordion.d.ts +52 -0
- package/dist/Accordion.js +192 -0
- package/dist/AchievementToast.d.ts +36 -0
- package/dist/AchievementToast.js +162 -0
- package/dist/AgentCard.d.ts +41 -0
- package/dist/AgentCard.js +168 -0
- package/dist/ArcadeButtons.d.ts +23 -0
- package/dist/ArcadeButtons.js +169 -0
- package/dist/AuroraBands.d.ts +19 -0
- package/dist/AuroraBands.js +126 -0
- package/dist/AvatarTooltips.d.ts +32 -0
- package/dist/AvatarTooltips.js +121 -0
- package/dist/BarRace.d.ts +39 -0
- package/dist/BarRace.js +227 -0
- package/dist/BentoGrid.d.ts +50 -0
- package/dist/BentoGrid.js +145 -0
- package/dist/BootSequence.d.ts +48 -0
- package/dist/BootSequence.js +234 -0
- package/dist/BreadcrumbTrail.d.ts +31 -0
- package/dist/BreadcrumbTrail.js +181 -0
- package/dist/CRTPower.d.ts +30 -0
- package/dist/CRTPower.js +142 -0
- package/dist/CardDeck.d.ts +29 -0
- package/dist/CardDeck.js +154 -0
- package/dist/ChangelogTimeline.d.ts +35 -0
- package/dist/ChangelogTimeline.js +137 -0
- package/dist/ChapterProgress.d.ts +23 -0
- package/dist/ChapterProgress.js +211 -0
- package/dist/ChatBubbles.d.ts +42 -0
- package/dist/ChatBubbles.js +198 -0
- package/dist/ChiptuneKit.d.ts +158 -0
- package/dist/ChiptuneKit.js +207 -0
- package/dist/CipherCard.d.ts +22 -0
- package/dist/CipherCard.js +91 -0
- package/dist/CloudSky.d.ts +28 -0
- package/dist/CloudSky.js +222 -0
- package/dist/CodeRain.d.ts +24 -0
- package/dist/CodeRain.js +158 -0
- package/dist/CodeShowcase.d.ts +50 -0
- package/dist/CodeShowcase.js +307 -0
- package/dist/ColorDial.d.ts +42 -0
- package/dist/ColorDial.js +288 -0
- package/dist/CommandPalette.d.ts +59 -0
- package/dist/CommandPalette.js +349 -0
- package/dist/CompareSlider.d.ts +33 -0
- package/dist/CompareSlider.js +152 -0
- package/dist/Confetti.d.ts +61 -0
- package/dist/Confetti.js +176 -0
- package/dist/ConnectBeams.d.ts +39 -0
- package/dist/ConnectBeams.js +132 -0
- package/dist/ContextOrb.d.ts +34 -0
- package/dist/ContextOrb.js +269 -0
- package/dist/ContourLines.d.ts +20 -0
- package/dist/ContourLines.js +159 -0
- package/dist/Coverflow.d.ts +27 -0
- package/dist/Coverflow.js +167 -0
- package/dist/CursorAttractor.d.ts +21 -0
- package/dist/CursorAttractor.js +136 -0
- package/dist/CutReveal.d.ts +21 -0
- package/dist/CutReveal.js +116 -0
- package/dist/DateRange.d.ts +45 -0
- package/dist/DateRange.js +327 -0
- package/dist/DeviceFrame.d.ts +30 -0
- package/dist/DeviceFrame.js +145 -0
- package/dist/DiffReveal.d.ts +36 -0
- package/dist/DiffReveal.js +247 -0
- package/dist/DirectionHover.d.ts +15 -0
- package/dist/DirectionHover.js +90 -0
- package/dist/Discard.d.ts +18 -0
- package/dist/Discard.js +61 -0
- package/dist/DitherField.d.ts +15 -0
- package/dist/DitherField.js +157 -0
- package/dist/DotGlobe.d.ts +48 -0
- package/dist/DotGlobe.js +312 -0
- package/dist/DotMap.d.ts +47 -0
- package/dist/DotMap.js +172 -0
- package/dist/DropZone.d.ts +57 -0
- package/dist/DropZone.js +304 -0
- package/dist/DynamicIsland.d.ts +32 -0
- package/dist/DynamicIsland.js +92 -0
- package/dist/EdgeFX.d.ts +27 -0
- package/dist/EdgeFX.js +98 -0
- package/dist/ElasticString.d.ts +22 -0
- package/dist/ElasticString.js +127 -0
- package/dist/ExpandCard.d.ts +44 -0
- package/dist/ExpandCard.js +182 -0
- package/dist/FeatureTabs.d.ts +34 -0
- package/dist/FeatureTabs.js +169 -0
- package/dist/FeedList.d.ts +37 -0
- package/dist/FeedList.js +163 -0
- package/dist/FlickerGrid.d.ts +29 -0
- package/dist/FlickerGrid.js +156 -0
- package/dist/FocusGrid.d.ts +20 -0
- package/dist/FocusGrid.js +48 -0
- package/dist/FocusPull.d.ts +26 -0
- package/dist/FocusPull.js +106 -0
- package/dist/Footprints.d.ts +24 -0
- package/dist/Footprints.js +126 -0
- package/dist/FunnelFlow.d.ts +34 -0
- package/dist/FunnelFlow.js +267 -0
- package/dist/GameOver.d.ts +46 -0
- package/dist/GameOver.js +191 -0
- package/dist/GaugeMeter.d.ts +38 -0
- package/dist/GaugeMeter.js +195 -0
- package/dist/GlassPanel.d.ts +27 -0
- package/dist/GlassPanel.js +80 -0
- package/dist/GrainFX.d.ts +34 -0
- package/dist/GrainFX.js +122 -0
- package/dist/GravityBox.d.ts +30 -0
- package/dist/GravityBox.js +220 -0
- package/dist/HealthBar.d.ts +33 -0
- package/dist/HealthBar.js +140 -0
- package/dist/Heatmap.d.ts +42 -0
- package/dist/Heatmap.js +232 -0
- package/dist/HexField.d.ts +29 -0
- package/dist/HexField.js +188 -0
- package/dist/HoldToConfirm.d.ts +29 -0
- package/dist/HoldToConfirm.js +163 -0
- package/dist/HorizontalTrack.d.ts +28 -0
- package/dist/HorizontalTrack.js +195 -0
- package/dist/HotbarDock.d.ts +40 -0
- package/dist/HotbarDock.js +148 -0
- package/dist/InkText.d.ts +27 -0
- package/dist/InkText.js +65 -0
- package/dist/InlineEdit.d.ts +30 -0
- package/dist/InlineEdit.js +198 -0
- package/dist/InteractiveGrid.d.ts +25 -0
- package/dist/InteractiveGrid.js +194 -0
- package/dist/InventoryGrid.d.ts +45 -0
- package/dist/InventoryGrid.js +272 -0
- package/dist/JellyBlob.d.ts +30 -0
- package/dist/JellyBlob.js +209 -0
- package/dist/KineticHeadline.d.ts +30 -0
- package/dist/KineticHeadline.js +133 -0
- package/dist/LavaLamp.d.ts +21 -0
- package/dist/LavaLamp.js +133 -0
- package/dist/LetterSwap.d.ts +20 -0
- package/dist/LetterSwap.js +78 -0
- package/dist/LevelMap.d.ts +35 -0
- package/dist/LevelMap.js +189 -0
- package/dist/LightShafts.d.ts +22 -0
- package/dist/LightShafts.js +170 -0
- package/dist/LightboxGallery.d.ts +26 -0
- package/dist/LightboxGallery.js +327 -0
- package/dist/LinkPeek.d.ts +36 -0
- package/dist/LinkPeek.js +194 -0
- package/dist/LogoOrbit.d.ts +37 -0
- package/dist/LogoOrbit.js +117 -0
- package/dist/Marquee.d.ts +33 -0
- package/dist/Marquee.js +148 -0
- package/dist/MarqueeLine.d.ts +33 -0
- package/dist/MarqueeLine.js +167 -0
- package/dist/MasonryWall.d.ts +13 -0
- package/dist/MasonryWall.js +90 -0
- package/dist/MegaMenu.d.ts +32 -0
- package/dist/MegaMenu.js +280 -0
- package/dist/MeteorShower.d.ts +24 -0
- package/dist/MeteorShower.js +155 -0
- package/dist/Minimap.d.ts +21 -0
- package/dist/Minimap.js +236 -0
- package/dist/MobileTabBar.d.ts +38 -0
- package/dist/MobileTabBar.js +148 -0
- package/dist/MorphDialog.d.ts +34 -0
- package/dist/MorphDialog.js +199 -0
- package/dist/MorphPopover.d.ts +33 -0
- package/dist/MorphPopover.js +168 -0
- package/dist/MorphWords.d.ts +18 -0
- package/dist/MorphWords.js +136 -0
- package/dist/OTPInput.d.ts +43 -0
- package/dist/OTPInput.js +174 -0
- package/dist/OverlayKit.d.ts +97 -0
- package/dist/OverlayKit.js +466 -0
- package/dist/OverlayMenu.d.ts +32 -0
- package/dist/OverlayMenu.js +154 -0
- package/dist/ParallaxCollage.d.ts +41 -0
- package/dist/ParallaxCollage.js +143 -0
- package/dist/PasswordMeter.d.ts +44 -0
- package/dist/PasswordMeter.js +165 -0
- package/dist/PegBoard.d.ts +26 -0
- package/dist/PegBoard.js +184 -0
- package/dist/PinCard.d.ts +21 -0
- package/dist/PinCard.js +84 -0
- package/dist/PixelAvatar.d.ts +33 -0
- package/dist/PixelAvatar.js +144 -0
- package/dist/PixelButton.d.ts +20 -0
- package/dist/PixelButton.js +128 -0
- package/dist/PixelExplode.d.ts +31 -0
- package/dist/PixelExplode.js +164 -0
- package/dist/PixelLoader.d.ts +32 -0
- package/dist/PixelLoader.js +142 -0
- package/dist/PixelParallax.d.ts +41 -0
- package/dist/PixelParallax.js +151 -0
- package/dist/PixelSpinners.d.ts +21 -0
- package/dist/PixelSpinners.js +110 -0
- package/dist/PixelType.d.ts +26 -0
- package/dist/PixelType.js +220 -0
- package/dist/PointerKit.d.ts +23 -0
- package/dist/PointerKit.js +222 -0
- package/dist/Polaroids.d.ts +41 -0
- package/dist/Polaroids.js +293 -0
- package/dist/PressStart.d.ts +28 -0
- package/dist/PressStart.js +99 -0
- package/dist/PricingFlip.d.ts +52 -0
- package/dist/PricingFlip.js +190 -0
- package/dist/ProximityType.d.ts +26 -0
- package/dist/ProximityType.js +135 -0
- package/dist/QuestDialog.d.ts +50 -0
- package/dist/QuestDialog.js +204 -0
- package/dist/QuestLog.d.ts +39 -0
- package/dist/QuestLog.js +214 -0
- package/dist/RangeDual.d.ts +34 -0
- package/dist/RangeDual.js +238 -0
- package/dist/RatingPips.d.ts +25 -0
- package/dist/RatingPips.js +129 -0
- package/dist/RetroHorizon.d.ts +27 -0
- package/dist/RetroHorizon.js +169 -0
- package/dist/Reveal.d.ts +30 -0
- package/dist/Reveal.js +92 -0
- package/dist/RingProgress.d.ts +45 -0
- package/dist/RingProgress.js +180 -0
- package/dist/RollingNumber.d.ts +28 -0
- package/dist/RollingNumber.js +108 -0
- package/dist/ScanScope.d.ts +24 -0
- package/dist/ScanScope.js +164 -0
- package/dist/ScoreTicker.d.ts +32 -0
- package/dist/ScoreTicker.js +176 -0
- package/dist/ScreenScroller.d.ts +24 -0
- package/dist/ScreenScroller.js +138 -0
- package/dist/Screensaver.d.ts +31 -0
- package/dist/Screensaver.js +221 -0
- package/dist/ScrollTilt.d.ts +27 -0
- package/dist/ScrollTilt.js +100 -0
- package/dist/ScrollTypography.d.ts +26 -0
- package/dist/ScrollTypography.js +124 -0
- package/dist/ScrollZoom.d.ts +31 -0
- package/dist/ScrollZoom.js +123 -0
- package/dist/ScrubNumber.d.ts +29 -0
- package/dist/ScrubNumber.js +152 -0
- package/dist/ShadowStack.d.ts +28 -0
- package/dist/ShadowStack.js +116 -0
- package/dist/SideRail.d.ts +43 -0
- package/dist/SideRail.js +253 -0
- package/dist/SignalText.d.ts +25 -0
- package/dist/SignalText.js +178 -0
- package/dist/SkeletonShimmer.d.ts +18 -0
- package/dist/SkeletonShimmer.js +111 -0
- package/dist/SketchHighlight.d.ts +27 -0
- package/dist/SketchHighlight.js +180 -0
- package/dist/SlideTabs.d.ts +40 -0
- package/dist/SlideTabs.js +190 -0
- package/dist/SmartNavbar.d.ts +48 -0
- package/dist/SmartNavbar.js +188 -0
- package/dist/SparkChart.d.ts +41 -0
- package/dist/SparkChart.js +188 -0
- package/dist/Spoiler.d.ts +22 -0
- package/dist/Spoiler.js +97 -0
- package/dist/SpotlightTour.d.ts +38 -0
- package/dist/SpotlightTour.js +231 -0
- package/dist/SpringDrawer.d.ts +39 -0
- package/dist/SpringDrawer.js +360 -0
- package/dist/SpriteAnimator.d.ts +41 -0
- package/dist/SpriteAnimator.js +124 -0
- package/dist/StatCard.d.ts +43 -0
- package/dist/StatCard.js +168 -0
- package/dist/StepLoader.d.ts +41 -0
- package/dist/StepLoader.js +191 -0
- package/dist/StepperForm.d.ts +41 -0
- package/dist/StepperForm.js +206 -0
- package/dist/StickerBoard.d.ts +39 -0
- package/dist/StickerBoard.js +209 -0
- package/dist/StickyReveal.d.ts +42 -0
- package/dist/StickyReveal.js +181 -0
- package/dist/StoryViewer.d.ts +36 -0
- package/dist/StoryViewer.js +175 -0
- package/dist/StreamingText.d.ts +29 -0
- package/dist/StreamingText.js +271 -0
- package/dist/SuggestionChips.d.ts +32 -0
- package/dist/SuggestionChips.js +96 -0
- package/dist/SwipeActions.d.ts +30 -0
- package/dist/SwipeActions.js +141 -0
- package/dist/TagInput.d.ts +30 -0
- package/dist/TagInput.js +284 -0
- package/dist/TallyUp.d.ts +38 -0
- package/dist/TallyUp.js +157 -0
- package/dist/TerminalDemo.d.ts +63 -0
- package/dist/TerminalDemo.js +214 -0
- package/dist/TestimonialWall.d.ts +35 -0
- package/dist/TestimonialWall.js +131 -0
- package/dist/TextOnPath.d.ts +36 -0
- package/dist/TextOnPath.js +130 -0
- package/dist/ThinkingShimmer.d.ts +36 -0
- package/dist/ThinkingShimmer.js +132 -0
- package/dist/ToastStack.d.ts +62 -0
- package/dist/ToastStack.js +289 -0
- package/dist/ToggleGroup.d.ts +39 -0
- package/dist/ToggleGroup.js +190 -0
- package/dist/ToggleKit.d.ts +70 -0
- package/dist/ToggleKit.js +229 -0
- package/dist/TracingLine.d.ts +24 -0
- package/dist/TracingLine.js +139 -0
- package/dist/TradingCard.d.ts +30 -0
- package/dist/TradingCard.js +147 -0
- package/dist/VanishInput.d.ts +34 -0
- package/dist/VanishInput.js +190 -0
- package/dist/VideoHero.d.ts +32 -0
- package/dist/VideoHero.js +207 -0
- package/dist/VoiceOrb.d.ts +23 -0
- package/dist/VoiceOrb.js +182 -0
- package/dist/VoxelTiles.d.ts +38 -0
- package/dist/VoxelTiles.js +201 -0
- package/dist/WarpField.d.ts +18 -0
- package/dist/WarpField.js +160 -0
- package/dist/WebcamPixels.d.ts +38 -0
- package/dist/WebcamPixels.js +292 -0
- package/dist/WheelPicker.d.ts +29 -0
- package/dist/WheelPicker.js +199 -0
- package/dist/WobbleCard.d.ts +23 -0
- package/dist/WobbleCard.js +112 -0
- package/dist/index.d.ts +158 -0
- package/dist/index.js +159 -0
- package/package.json +34 -4
package/dist/LevelMap.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useInsertionEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
const STYLE_ID = "bl-level-map";
|
|
5
|
+
const CSS = `
|
|
6
|
+
.bl-lvl { position: relative; width: 100%; font-family: var(--bl-font, "Press Start 2P", ui-monospace, monospace); }
|
|
7
|
+
.bl-lvl__svg { position: absolute; inset: 0; overflow: visible; pointer-events: none; }
|
|
8
|
+
.bl-lvl__reveal { stroke-dasharray: 1; stroke-dashoffset: 1; animation: bl-lvl-draw var(--bl-draw) steps(24) 200ms forwards; }
|
|
9
|
+
.bl-lvl__node { position: absolute; display: grid; place-items: center; width: var(--bl-node); height: var(--bl-node); margin: calc(var(--bl-node) / -2) 0 0 calc(var(--bl-node) / -2); padding: 0; border: 0; cursor: pointer;
|
|
10
|
+
background: var(--bl-face); color: #0b0b14; font-size: calc(var(--bl-node) / 4);
|
|
11
|
+
box-shadow: 0 -4px 0 0 #0b0b14, 0 4px 0 0 #0b0b14, -4px 0 0 0 #0b0b14, 4px 0 0 0 #0b0b14, inset -4px -4px 0 0 rgba(0,0,0,0.25), inset 4px 4px 0 0 rgba(255,255,255,0.3); }
|
|
12
|
+
.bl-lvl__node:hover:not([aria-disabled="true"]) { filter: brightness(1.12); transform: translateY(-2px); }
|
|
13
|
+
.bl-lvl__node:focus-visible { outline: 4px solid #f4f4f4; outline-offset: 6px; }
|
|
14
|
+
.bl-lvl__node[aria-disabled="true"] { cursor: not-allowed; filter: grayscale(1) brightness(0.6); }
|
|
15
|
+
.bl-lvl__node[data-status="current"] { animation: bl-lvl-pulse 1s steps(2) infinite; }
|
|
16
|
+
.bl-lvl__marker { position: absolute; left: 50%; bottom: calc(100% + 8px); transform: translateX(-50%); animation: bl-lvl-bounce 0.7s steps(3) infinite alternate; pointer-events: none; }
|
|
17
|
+
.bl-lvl__name { position: absolute; top: calc(100% + 12px); left: 50%; transform: translateX(-50%); width: max-content; max-width: 140px; color: var(--bl-text); font-size: 8px; line-height: 1.5; text-align: center; text-transform: uppercase; pointer-events: none; }
|
|
18
|
+
.bl-lvl__stars { display: block; margin-top: 4px; color: #ffcd75; letter-spacing: 2px; }
|
|
19
|
+
@keyframes bl-lvl-draw { to { stroke-dashoffset: 0; } }
|
|
20
|
+
@keyframes bl-lvl-pulse { 50% { box-shadow: 0 -4px 0 0 #f4f4f4, 0 4px 0 0 #f4f4f4, -4px 0 0 0 #f4f4f4, 4px 0 0 0 #f4f4f4, inset -4px -4px 0 0 rgba(0,0,0,0.25), inset 4px 4px 0 0 rgba(255,255,255,0.3); } }
|
|
21
|
+
@keyframes bl-lvl-bounce { to { transform: translate(-50%, -8px); } }
|
|
22
|
+
@media (prefers-reduced-motion: reduce) {
|
|
23
|
+
.bl-lvl__reveal { animation: none; stroke-dashoffset: 0; }
|
|
24
|
+
.bl-lvl__node[data-status="current"], .bl-lvl__marker { animation: none; }
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
27
|
+
function useStyles() {
|
|
28
|
+
useInsertionEffect(() => {
|
|
29
|
+
if (typeof document === "undefined") return;
|
|
30
|
+
const style = document.getElementById(STYLE_ID) ?? Object.assign(document.createElement("style"), { id: STYLE_ID });
|
|
31
|
+
style.textContent = CSS;
|
|
32
|
+
if (!style.isConnected) document.head.appendChild(style);
|
|
33
|
+
}, []);
|
|
34
|
+
}
|
|
35
|
+
const Lock = () => /* @__PURE__ */ jsxs("svg", { width: "45%", height: "45%", viewBox: "0 0 8 8", shapeRendering: "crispEdges", fill: "#0b0b14", "aria-hidden": "true", children: [
|
|
36
|
+
/* @__PURE__ */ jsx("rect", { x: "2", y: "0", width: "4", height: "1" }),
|
|
37
|
+
/* @__PURE__ */ jsx("rect", { x: "1", y: "1", width: "1", height: "3" }),
|
|
38
|
+
/* @__PURE__ */ jsx("rect", { x: "6", y: "1", width: "1", height: "3" }),
|
|
39
|
+
/* @__PURE__ */ jsx("rect", { x: "0", y: "4", width: "8", height: "4" })
|
|
40
|
+
] });
|
|
41
|
+
const STATUS_COLORS = { cleared: "#38b764", current: "#ffcd75", available: "#41a6f6", locked: "#566c86" };
|
|
42
|
+
function layout(count, width, { nodeSize, minSpacing, rowGap, padding }) {
|
|
43
|
+
const inner = Math.max(nodeSize, width - padding * 2 - nodeSize);
|
|
44
|
+
const perRow = Math.max(2, Math.floor(inner / minSpacing) + 1);
|
|
45
|
+
const spacing = inner / (perRow - 1);
|
|
46
|
+
const points = Array.from({ length: count }, (_, i) => {
|
|
47
|
+
const row = Math.floor(i / perRow);
|
|
48
|
+
const col = i % perRow;
|
|
49
|
+
const x = padding + nodeSize / 2 + (row % 2 ? perRow - 1 - col : col) * spacing;
|
|
50
|
+
const y = padding + nodeSize / 2 + 40 + row * rowGap + Math.sin(col * 1.3 + row) * rowGap * 0.12;
|
|
51
|
+
return { x, y, row };
|
|
52
|
+
});
|
|
53
|
+
const rows = Math.ceil(count / perRow);
|
|
54
|
+
return { points, height: padding * 2 + nodeSize + 40 + (rows - 1) * rowGap + 70 };
|
|
55
|
+
}
|
|
56
|
+
function pathThrough(points) {
|
|
57
|
+
if (!points.length) return "";
|
|
58
|
+
let d = `M${points[0].x} ${points[0].y}`;
|
|
59
|
+
for (let i = 1; i < points.length; i++) {
|
|
60
|
+
const a = points[i - 1];
|
|
61
|
+
const b = points[i];
|
|
62
|
+
if (a.row === b.row) {
|
|
63
|
+
d += ` Q${(a.x + b.x) / 2} ${(a.y + b.y) / 2 - 18} ${b.x} ${b.y}`;
|
|
64
|
+
} else {
|
|
65
|
+
const bulge = a.x > b.x || a.row % 2 === 0 ? 80 : -80;
|
|
66
|
+
d += ` C${a.x + bulge} ${a.y} ${b.x + bulge} ${b.y} ${b.x} ${b.y}`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return d;
|
|
70
|
+
}
|
|
71
|
+
const DEFAULT_LEVELS = [
|
|
72
|
+
{ id: 1, name: "Spawn point", status: "cleared", stars: 3 },
|
|
73
|
+
{ id: 2, name: "Oak woods", status: "cleared", stars: 2 },
|
|
74
|
+
{ id: 3, name: "Copper cave", status: "cleared", stars: 3 },
|
|
75
|
+
{ id: 4, name: "Sunken temple", status: "current" },
|
|
76
|
+
{ id: 5, name: "Lava bridge", status: "available" },
|
|
77
|
+
{ id: 6, name: "Sky isles", status: "locked" },
|
|
78
|
+
{ id: 7, name: "Crystal depths", status: "locked" },
|
|
79
|
+
{ id: 8, name: "The dragon", status: "locked" }
|
|
80
|
+
];
|
|
81
|
+
function LevelMap({
|
|
82
|
+
levels = DEFAULT_LEVELS,
|
|
83
|
+
nodeSize = 56,
|
|
84
|
+
minSpacing = 130,
|
|
85
|
+
rowGap = 150,
|
|
86
|
+
padding = 24,
|
|
87
|
+
pathColor = "#566c86",
|
|
88
|
+
clearedColor = "#a7f070",
|
|
89
|
+
textColor = "#f4f4f4",
|
|
90
|
+
marker,
|
|
91
|
+
drawDuration = 1200,
|
|
92
|
+
fontFamily,
|
|
93
|
+
onSelect,
|
|
94
|
+
className = "",
|
|
95
|
+
style
|
|
96
|
+
}) {
|
|
97
|
+
useStyles();
|
|
98
|
+
const maskId = `bl-lvl-mask-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
99
|
+
const rootRef = useRef(null);
|
|
100
|
+
const nodeRefs = useRef([]);
|
|
101
|
+
const [width, setWidth] = useState(640);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const root = rootRef.current;
|
|
104
|
+
if (!root) return void 0;
|
|
105
|
+
const observer = new ResizeObserver(([entry]) => setWidth(entry.contentRect.width));
|
|
106
|
+
observer.observe(root);
|
|
107
|
+
return () => observer.disconnect();
|
|
108
|
+
}, []);
|
|
109
|
+
const { points, height } = useMemo(
|
|
110
|
+
() => layout(levels.length, width, { nodeSize, minSpacing, rowGap, padding }),
|
|
111
|
+
[levels.length, width, nodeSize, minSpacing, rowGap, padding]
|
|
112
|
+
);
|
|
113
|
+
const fullPath = useMemo(() => pathThrough(points), [points]);
|
|
114
|
+
const progressIndex = Math.max(0, levels.findIndex((level) => level.status === "current"), levels.filter((level) => level.status === "cleared").length - 1);
|
|
115
|
+
const clearedPath = useMemo(() => pathThrough(points.slice(0, progressIndex + 1)), [points, progressIndex]);
|
|
116
|
+
const focusNode = (index) => nodeRefs.current[Math.max(0, Math.min(levels.length - 1, index))]?.focus();
|
|
117
|
+
return /* @__PURE__ */ jsxs(
|
|
118
|
+
"div",
|
|
119
|
+
{
|
|
120
|
+
ref: rootRef,
|
|
121
|
+
className: `bl-lvl ${className}`,
|
|
122
|
+
role: "list",
|
|
123
|
+
"aria-label": "Level map",
|
|
124
|
+
style: { height, "--bl-node": `${nodeSize}px`, "--bl-text": textColor, "--bl-draw": `${drawDuration}ms`, ...fontFamily ? { "--bl-font": fontFamily } : null, ...style },
|
|
125
|
+
children: [
|
|
126
|
+
/* @__PURE__ */ jsxs("svg", { className: "bl-lvl__svg", width: "100%", height, "aria-hidden": "true", shapeRendering: "crispEdges", children: [
|
|
127
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("mask", { id: maskId, maskUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { className: "bl-lvl__reveal", d: clearedPath, pathLength: "1", fill: "none", stroke: "#fff", strokeWidth: "24" }, progressIndex) }) }),
|
|
128
|
+
/* @__PURE__ */ jsx("path", { d: fullPath, fill: "none", stroke: pathColor, strokeWidth: "6", strokeDasharray: "6 12", strokeLinecap: "square" }),
|
|
129
|
+
/* @__PURE__ */ jsx(
|
|
130
|
+
"path",
|
|
131
|
+
{
|
|
132
|
+
d: clearedPath,
|
|
133
|
+
fill: "none",
|
|
134
|
+
stroke: clearedColor,
|
|
135
|
+
strokeWidth: "8",
|
|
136
|
+
strokeDasharray: "8 10",
|
|
137
|
+
strokeLinecap: "square",
|
|
138
|
+
mask: `url(#${maskId})`
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
] }),
|
|
142
|
+
levels.map((level, index) => {
|
|
143
|
+
const point = points[index];
|
|
144
|
+
const locked = level.status === "locked";
|
|
145
|
+
return /* @__PURE__ */ jsx("div", { role: "listitem", children: /* @__PURE__ */ jsxs(
|
|
146
|
+
"button",
|
|
147
|
+
{
|
|
148
|
+
ref: (el) => {
|
|
149
|
+
nodeRefs.current[index] = el;
|
|
150
|
+
},
|
|
151
|
+
type: "button",
|
|
152
|
+
className: "bl-lvl__node",
|
|
153
|
+
"data-status": level.status,
|
|
154
|
+
"aria-disabled": locked || void 0,
|
|
155
|
+
"aria-current": level.status === "current" ? "step" : void 0,
|
|
156
|
+
"aria-label": `Level ${index + 1}${level.name ? `: ${level.name}` : ""}, ${level.status}${level.stars ? `, ${level.stars} of 3 stars` : ""}`,
|
|
157
|
+
style: { left: point.x, top: point.y, "--bl-face": STATUS_COLORS[level.status] ?? STATUS_COLORS.available },
|
|
158
|
+
onClick: () => !locked && onSelect?.(level, index),
|
|
159
|
+
onKeyDown: (event) => {
|
|
160
|
+
if (event.key === "ArrowRight" || event.key === "ArrowDown") {
|
|
161
|
+
event.preventDefault();
|
|
162
|
+
focusNode(index + 1);
|
|
163
|
+
}
|
|
164
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
|
|
165
|
+
event.preventDefault();
|
|
166
|
+
focusNode(index - 1);
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
children: [
|
|
170
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: locked ? /* @__PURE__ */ jsx(Lock, {}) : level.status === "cleared" ? "\u2713" : level.label ?? index + 1 }),
|
|
171
|
+
level.status === "current" && /* @__PURE__ */ jsx("span", { className: "bl-lvl__marker", "aria-hidden": "true", children: marker ?? /* @__PURE__ */ jsx("span", { style: { fontSize: 22, color: "#ffcd75" }, children: "\u25BC" }) }),
|
|
172
|
+
level.name && /* @__PURE__ */ jsxs("span", { className: "bl-lvl__name", "aria-hidden": "true", children: [
|
|
173
|
+
level.name,
|
|
174
|
+
level.stars ? /* @__PURE__ */ jsxs("span", { className: "bl-lvl__stars", children: [
|
|
175
|
+
"\u2605".repeat(level.stars),
|
|
176
|
+
"\u2606".repeat(3 - level.stars)
|
|
177
|
+
] }) : null
|
|
178
|
+
] })
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
) }, level.id ?? index);
|
|
182
|
+
})
|
|
183
|
+
]
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
export {
|
|
188
|
+
LevelMap as default
|
|
189
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type CSSProperties } from 'react';
|
|
2
|
+
export interface LightShaftsProps {
|
|
3
|
+
/** Swaying rays from a source, flickering floor pillars, or forked lightning with a flash. */
|
|
4
|
+
mode?: 'rays' | 'beams' | 'lightning';
|
|
5
|
+
/** Rays or pillars. */
|
|
6
|
+
count?: number;
|
|
7
|
+
speed?: number;
|
|
8
|
+
/** Light source position as a share of the area. */
|
|
9
|
+
originX?: number;
|
|
10
|
+
originY?: number;
|
|
11
|
+
/** Fan angle of the rays in degrees. */
|
|
12
|
+
spread?: number;
|
|
13
|
+
/** Roughly how often lightning strikes, in ms. */
|
|
14
|
+
interval?: number;
|
|
15
|
+
pixelSize?: number;
|
|
16
|
+
/** [main, second]. */
|
|
17
|
+
colors?: string[];
|
|
18
|
+
backgroundColor?: string;
|
|
19
|
+
className?: string;
|
|
20
|
+
style?: CSSProperties;
|
|
21
|
+
}
|
|
22
|
+
export default function LightShafts({ mode, count, speed, originX, originY, spread, interval, pixelSize, colors, backgroundColor, className, style }: LightShaftsProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
const hexToRgb = (hex) => {
|
|
5
|
+
const n = parseInt(hex.replace("#", "").replace(/^(.)(.)(.)$/, "$1$1$2$2$3$3"), 16);
|
|
6
|
+
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
7
|
+
};
|
|
8
|
+
const rgba = ([r, g, b], a) => `rgba(${r},${g},${b},${a})`;
|
|
9
|
+
function bolt(x, y, length, angle, depth, out) {
|
|
10
|
+
const segs = 10;
|
|
11
|
+
let px = x;
|
|
12
|
+
let py = y;
|
|
13
|
+
for (let i = 0; i < segs; i++) {
|
|
14
|
+
const a = angle + (Math.random() - 0.5) * 0.9;
|
|
15
|
+
const nx = px + Math.cos(a) * (length / segs);
|
|
16
|
+
const ny = py + Math.sin(a) * (length / segs);
|
|
17
|
+
out.push([px, py, nx, ny, depth]);
|
|
18
|
+
if (depth < 2 && Math.random() < 0.18) bolt(nx, ny, length * 0.45, a + (Math.random() < 0.5 ? -0.6 : 0.6), depth + 1, out);
|
|
19
|
+
px = nx;
|
|
20
|
+
py = ny;
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
function LightShafts({
|
|
25
|
+
mode = "rays",
|
|
26
|
+
count = 7,
|
|
27
|
+
speed = 1,
|
|
28
|
+
originX = 0.5,
|
|
29
|
+
originY = -0.05,
|
|
30
|
+
spread = 70,
|
|
31
|
+
interval = 3500,
|
|
32
|
+
pixelSize = 3,
|
|
33
|
+
colors = ["#ffcd75", "#f4f4f4"],
|
|
34
|
+
backgroundColor = "#1a1c2c",
|
|
35
|
+
className = "",
|
|
36
|
+
style
|
|
37
|
+
}) {
|
|
38
|
+
const canvasRef = useRef(null);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const canvas = canvasRef.current;
|
|
41
|
+
const ctx = canvas.getContext("2d");
|
|
42
|
+
const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
43
|
+
const main = hexToRgb(colors[0]);
|
|
44
|
+
const second = hexToRgb(colors[1] ?? colors[0]);
|
|
45
|
+
const bg = hexToRgb(backgroundColor);
|
|
46
|
+
let w = 0;
|
|
47
|
+
let h = 0;
|
|
48
|
+
let t = 2;
|
|
49
|
+
let raf = 0;
|
|
50
|
+
let last = 0;
|
|
51
|
+
let visible = true;
|
|
52
|
+
let strike = null;
|
|
53
|
+
let nextStrike = 600;
|
|
54
|
+
const pillars = Array.from({ length: count }, (_, i) => ({ x: (i + 0.5) / count + Math.sin(i * 7.1) * 0.3 / count, width: 0.4 + i * 37 % 10 / 20, phase: i * 1.7 }));
|
|
55
|
+
const fit = () => {
|
|
56
|
+
w = Math.max(1, Math.ceil(canvas.clientWidth / pixelSize));
|
|
57
|
+
h = Math.max(1, Math.ceil(canvas.clientHeight / pixelSize));
|
|
58
|
+
canvas.width = w;
|
|
59
|
+
canvas.height = h;
|
|
60
|
+
ctx.imageSmoothingEnabled = false;
|
|
61
|
+
};
|
|
62
|
+
const rays = () => {
|
|
63
|
+
const ox = originX * w;
|
|
64
|
+
const oy = originY * h;
|
|
65
|
+
const reach = Math.hypot(w, h) * 1.1;
|
|
66
|
+
for (let i = 0; i < count; i++) {
|
|
67
|
+
const base = (i / Math.max(1, count - 1) - 0.5) * (spread * Math.PI / 180);
|
|
68
|
+
const a = Math.PI / 2 + base + Math.sin(t * 0.4 + i * 1.3) * 0.08;
|
|
69
|
+
const half = 0.03 + 0.025 * (0.5 + 0.5 * Math.sin(t * 0.7 + i * 2.1));
|
|
70
|
+
const glow = ctx.createLinearGradient(ox, oy, ox + Math.cos(a) * reach, oy + Math.sin(a) * reach);
|
|
71
|
+
const tint = i % 2 ? second : main;
|
|
72
|
+
const strength = 0.16 + 0.1 * Math.sin(t * 1.1 + i);
|
|
73
|
+
glow.addColorStop(0, rgba(tint, strength * 1.8));
|
|
74
|
+
glow.addColorStop(0.6, rgba(tint, strength * 0.5));
|
|
75
|
+
glow.addColorStop(1, rgba(tint, 0));
|
|
76
|
+
ctx.fillStyle = glow;
|
|
77
|
+
ctx.beginPath();
|
|
78
|
+
ctx.moveTo(ox, oy);
|
|
79
|
+
ctx.lineTo(ox + Math.cos(a - half) * reach, oy + Math.sin(a - half) * reach);
|
|
80
|
+
ctx.lineTo(ox + Math.cos(a + half) * reach, oy + Math.sin(a + half) * reach);
|
|
81
|
+
ctx.closePath();
|
|
82
|
+
ctx.fill();
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const beams = () => {
|
|
86
|
+
pillars.forEach((p, i) => {
|
|
87
|
+
const flicker = 0.55 + 0.25 * Math.sin(t * 3 + p.phase) + 0.2 * Math.sin(t * 7.3 + p.phase * 2);
|
|
88
|
+
const x = (p.x + Math.sin(t * 0.3 + p.phase) * 0.01) * w;
|
|
89
|
+
const bw = Math.max(1, w / count * p.width * 0.5);
|
|
90
|
+
const tint = i % 2 ? second : main;
|
|
91
|
+
const glow = ctx.createLinearGradient(0, h, 0, 0);
|
|
92
|
+
glow.addColorStop(0, rgba(tint, 0.55 * flicker));
|
|
93
|
+
glow.addColorStop(0.5, rgba(tint, 0.18 * flicker));
|
|
94
|
+
glow.addColorStop(1, rgba(tint, 0));
|
|
95
|
+
ctx.fillStyle = glow;
|
|
96
|
+
ctx.fillRect(Math.round(x - bw / 2), 0, Math.round(bw), h);
|
|
97
|
+
ctx.fillStyle = rgba(tint, 0.35 * flicker);
|
|
98
|
+
ctx.fillRect(Math.round(x), Math.round(h * 0.35), 1, h);
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
const lightning = (now) => {
|
|
102
|
+
if (!strike || now - strike.at > 700) return;
|
|
103
|
+
const age = (now - strike.at) / 700;
|
|
104
|
+
const flash = age < 0.08 || age > 0.16 && age < 0.22 ? 0.35 : 0;
|
|
105
|
+
if (flash) {
|
|
106
|
+
ctx.fillStyle = rgba(second, flash);
|
|
107
|
+
ctx.fillRect(0, 0, w, h);
|
|
108
|
+
}
|
|
109
|
+
ctx.fillStyle = rgba(main, 1 - age);
|
|
110
|
+
strike.segs.forEach(([x0, y0, x1, y1, depth]) => {
|
|
111
|
+
const steps = Math.max(1, Math.ceil(Math.hypot(x1 - x0, y1 - y0)));
|
|
112
|
+
for (let k = 0; k <= steps; k++) ctx.fillRect(Math.round(x0 + (x1 - x0) * k / steps), Math.round(y0 + (y1 - y0) * k / steps), depth ? 1 : 2, depth ? 1 : 2);
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
const draw = (now) => {
|
|
116
|
+
ctx.globalCompositeOperation = "source-over";
|
|
117
|
+
const [r, g, b] = bg;
|
|
118
|
+
ctx.fillStyle = `rgb(${r},${g},${b})`;
|
|
119
|
+
ctx.fillRect(0, 0, w, h);
|
|
120
|
+
ctx.globalCompositeOperation = "lighter";
|
|
121
|
+
if (mode === "beams") beams();
|
|
122
|
+
else if (mode === "lightning") lightning(now);
|
|
123
|
+
else rays();
|
|
124
|
+
ctx.globalCompositeOperation = "source-over";
|
|
125
|
+
};
|
|
126
|
+
const tick = (now) => {
|
|
127
|
+
const dt = Math.max(0, Math.min(0.05, (now - last) / 1e3));
|
|
128
|
+
last = now;
|
|
129
|
+
t += dt * speed;
|
|
130
|
+
if (mode === "lightning") {
|
|
131
|
+
nextStrike -= dt * 1e3;
|
|
132
|
+
if (nextStrike <= 0) {
|
|
133
|
+
strike = { at: now, segs: bolt(w * (0.2 + Math.random() * 0.6), 0, h * 0.95, Math.PI / 2, 0, []) };
|
|
134
|
+
nextStrike = interval * (0.6 + Math.random() * 0.8);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
draw(now);
|
|
138
|
+
raf = visible && !document.hidden ? requestAnimationFrame(tick) : 0;
|
|
139
|
+
};
|
|
140
|
+
const start = () => {
|
|
141
|
+
if (raf || reduced || !visible || document.hidden) return;
|
|
142
|
+
last = performance.now();
|
|
143
|
+
raf = requestAnimationFrame(tick);
|
|
144
|
+
};
|
|
145
|
+
const resize = new ResizeObserver(() => {
|
|
146
|
+
fit();
|
|
147
|
+
draw(performance.now());
|
|
148
|
+
});
|
|
149
|
+
resize.observe(canvas);
|
|
150
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
151
|
+
visible = entry.isIntersecting;
|
|
152
|
+
start();
|
|
153
|
+
});
|
|
154
|
+
observer.observe(canvas);
|
|
155
|
+
document.addEventListener("visibilitychange", start);
|
|
156
|
+
fit();
|
|
157
|
+
draw(performance.now());
|
|
158
|
+
start();
|
|
159
|
+
return () => {
|
|
160
|
+
cancelAnimationFrame(raf);
|
|
161
|
+
resize.disconnect();
|
|
162
|
+
observer.disconnect();
|
|
163
|
+
document.removeEventListener("visibilitychange", start);
|
|
164
|
+
};
|
|
165
|
+
}, [mode, count, speed, originX, originY, spread, interval, pixelSize, colors.join(), backgroundColor]);
|
|
166
|
+
return /* @__PURE__ */ jsx("canvas", { ref: canvasRef, "aria-hidden": "true", className, style: { display: "block", width: "100%", height: "100%", background: backgroundColor, imageRendering: "pixelated", ...style } });
|
|
167
|
+
}
|
|
168
|
+
export {
|
|
169
|
+
LightShafts as default
|
|
170
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode } from 'react';
|
|
2
|
+
export interface GalleryImage {
|
|
3
|
+
src: string;
|
|
4
|
+
alt?: string;
|
|
5
|
+
caption?: ReactNode;
|
|
6
|
+
/** A smaller image for the grid. */
|
|
7
|
+
thumb?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface LightboxGalleryProps {
|
|
10
|
+
images?: GalleryImage[];
|
|
11
|
+
/** Grid column width in px. */
|
|
12
|
+
thumbSize?: number;
|
|
13
|
+
gap?: number;
|
|
14
|
+
aspectRatio?: string;
|
|
15
|
+
radius?: number;
|
|
16
|
+
/** Applied to thumbs and the full image. */
|
|
17
|
+
imageStyle?: CSSProperties;
|
|
18
|
+
label?: string;
|
|
19
|
+
backdropColor?: string;
|
|
20
|
+
surfaceColor?: string;
|
|
21
|
+
accentColor?: string;
|
|
22
|
+
fontFamily?: string;
|
|
23
|
+
className?: string;
|
|
24
|
+
style?: CSSProperties;
|
|
25
|
+
}
|
|
26
|
+
export default function LightboxGallery({ images, thumbSize, gap, aspectRatio, radius, imageStyle, label, backdropColor, surfaceColor, accentColor, fontFamily, className, style }: LightboxGalleryProps): import("react").JSX.Element;
|