tink-harness 1.9.7 → 1.9.8
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/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,17 @@ All notable changes to Tink are tracked here.
|
|
|
6
6
|
|
|
7
7
|
No unreleased changes yet.
|
|
8
8
|
|
|
9
|
+
## [1.9.8] - 2026-06-11
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Galaxy-styled harness map background: a slowly rotating 4-arm spiral of 760 particles (pink-to-cyan, screen-blended), 7 colored nebula glows, a breathing core glow, and a deeper space gradient — inspired by a Three.js galaxy reference while keeping the SVG map fully interactive.
|
|
14
|
+
- Neural signal pulses: glowing dots travel along every edge from source to target (3.2-7.4s, staggered), so connections read like firing synapses.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Signal pulses follow the map state: they hide with core mode/filters, dim in focus mode, and stay bright only on edges related to the selected node. Clicking the galaxy background clears the selection. prefers-reduced-motion disables rotation and pulses.
|
|
19
|
+
|
|
9
20
|
## [1.9.7] - 2026-06-10
|
|
10
21
|
|
|
11
22
|
### Added
|
package/VERSIONING.md
CHANGED
package/package.json
CHANGED
|
@@ -673,6 +673,50 @@ function renderGraphCanvas(summary, copy) {
|
|
|
673
673
|
delay: seed % 5000
|
|
674
674
|
};
|
|
675
675
|
});
|
|
676
|
+
const GALAXY = { count: 760, arms: 4, radius: 360, spin: 2.3, power: 2.4, cx: 545, cy: 340, flatten: 0.6 };
|
|
677
|
+
const lerpChannel = (from, to, t) => Math.round(from + (to - from) * t);
|
|
678
|
+
const galaxyDots = Array.from({ length: GALAXY.count }, (_, index) => {
|
|
679
|
+
const s1 = (hashString(`gal:${index}:a`) % 10000) / 10000;
|
|
680
|
+
const s2 = (hashString(`gal:${index}:b`) % 10000) / 10000;
|
|
681
|
+
const s3 = (hashString(`gal:${index}:c`) % 10000) / 10000;
|
|
682
|
+
const s4 = (hashString(`gal:${index}:d`) % 10000) / 10000;
|
|
683
|
+
const radius = Math.pow(s1, GALAXY.power) * GALAXY.radius;
|
|
684
|
+
const t = radius / GALAXY.radius;
|
|
685
|
+
const branchAngle = ((index % GALAXY.arms) / GALAXY.arms) * Math.PI * 2;
|
|
686
|
+
const spinAngle = t * GALAXY.spin;
|
|
687
|
+
const randomX = (s2 - 0.5) * 0.42 * radius;
|
|
688
|
+
const randomY = (s3 - 0.5) * 0.42 * radius;
|
|
689
|
+
const totalAngle = branchAngle + spinAngle;
|
|
690
|
+
// inside #FF66FF -> outside #66FFFF, like the reference galaxy
|
|
691
|
+
const color = `rgb(${lerpChannel(255, 102, t)}, ${lerpChannel(102, 255, t)}, 255)`;
|
|
692
|
+
return {
|
|
693
|
+
x: (GALAXY.cx + (Math.cos(totalAngle) * radius + randomX)).toFixed(1),
|
|
694
|
+
y: (GALAXY.cy + (Math.sin(totalAngle) * radius + randomY) * GALAXY.flatten).toFixed(1),
|
|
695
|
+
r: (0.5 + s4 * 1.1).toFixed(1),
|
|
696
|
+
color,
|
|
697
|
+
opacity: (0.12 + s4 * 0.34).toFixed(2)
|
|
698
|
+
};
|
|
699
|
+
});
|
|
700
|
+
const nebulae = Array.from({ length: 7 }, (_, index) => {
|
|
701
|
+
const seed = hashString(`nebula:${index}`);
|
|
702
|
+
return {
|
|
703
|
+
id: index,
|
|
704
|
+
hue: seed % 360,
|
|
705
|
+
x: 80 + (seed % 930),
|
|
706
|
+
y: 60 + ((seed >> 5) % 560),
|
|
707
|
+
r: 70 + ((seed >> 3) % 150),
|
|
708
|
+
opacity: (0.05 + ((seed >> 7) % 8) / 100).toFixed(2)
|
|
709
|
+
};
|
|
710
|
+
});
|
|
711
|
+
const pulses = edges.slice(0, 120).map((edge, index) => {
|
|
712
|
+
const seed = hashString(`pulse:${edge.source}:${edge.target}:${index}`);
|
|
713
|
+
return {
|
|
714
|
+
path: `M ${edge.sourceNode.x.toFixed(1)},${edge.sourceNode.y.toFixed(1)} L ${edge.targetNode.x.toFixed(1)},${edge.targetNode.y.toFixed(1)}`,
|
|
715
|
+
dur: (3.2 + (seed % 42) / 10).toFixed(1),
|
|
716
|
+
begin: -((seed >> 4) % 7000),
|
|
717
|
+
index
|
|
718
|
+
};
|
|
719
|
+
});
|
|
676
720
|
const mapTitle = copy.knowledgeGraph || copy.harnessMap || 'Harness map';
|
|
677
721
|
const mapEyebrow = copy.harnessMap && copy.harnessMap !== mapTitle ? copy.harnessMap : '';
|
|
678
722
|
return `
|
|
@@ -698,9 +742,25 @@ function renderGraphCanvas(summary, copy) {
|
|
|
698
742
|
<svg class="graph-canvas" viewBox="0 0 1090 680" role="img" aria-label="Harness health graph">
|
|
699
743
|
<defs>
|
|
700
744
|
<radialGradient id="graph-bg-grad" cx="50%" cy="42%" r="80%">
|
|
701
|
-
<stop offset="0%" style="stop-color: #
|
|
702
|
-
<stop offset="60%" style="stop-color: #
|
|
703
|
-
<stop offset="100%" style="stop-color: #
|
|
745
|
+
<stop offset="0%" style="stop-color: #0B0E1A"/>
|
|
746
|
+
<stop offset="60%" style="stop-color: #05060F"/>
|
|
747
|
+
<stop offset="100%" style="stop-color: #000005"/>
|
|
748
|
+
</radialGradient>
|
|
749
|
+
<radialGradient id="galaxy-core-grad" cx="50%" cy="50%" r="50%">
|
|
750
|
+
<stop offset="0%" style="stop-color: #FFFFFF; stop-opacity: 0.55"/>
|
|
751
|
+
<stop offset="35%" style="stop-color: #C9B8FF; stop-opacity: 0.18"/>
|
|
752
|
+
<stop offset="100%" style="stop-color: #C9B8FF; stop-opacity: 0"/>
|
|
753
|
+
</radialGradient>
|
|
754
|
+
${nebulae.map((nebula) => `
|
|
755
|
+
<radialGradient id="nebula-grad-${nebula.id}" cx="50%" cy="50%" r="50%">
|
|
756
|
+
<stop offset="0%" style="stop-color: hsl(${nebula.hue}, 80%, 60%); stop-opacity: 0.6"/>
|
|
757
|
+
<stop offset="100%" style="stop-color: hsl(${nebula.hue}, 80%, 60%); stop-opacity: 0"/>
|
|
758
|
+
</radialGradient>
|
|
759
|
+
`).join('')}
|
|
760
|
+
<radialGradient id="pulse-grad" cx="50%" cy="50%" r="50%">
|
|
761
|
+
<stop offset="0%" style="stop-color: #FFFFFF; stop-opacity: 1"/>
|
|
762
|
+
<stop offset="45%" style="stop-color: #9DC4FF; stop-opacity: 0.85"/>
|
|
763
|
+
<stop offset="100%" style="stop-color: #5B8DEF; stop-opacity: 0"/>
|
|
704
764
|
</radialGradient>
|
|
705
765
|
${Object.entries(TYPE_COLORS).map(([type, color]) => `
|
|
706
766
|
<radialGradient id="node-grad-${escapeAttr(type)}" cx="32%" cy="28%" r="78%">
|
|
@@ -716,6 +776,15 @@ function renderGraphCanvas(summary, copy) {
|
|
|
716
776
|
<circle cx="${star.x}" cy="${star.y}" r="${star.r}" fill="#FFFFFF" opacity="${star.opacity}"${star.twinkle ? ` class="star-twinkle" style="--twinkle-delay: ${star.delay}ms"` : ''}/>
|
|
717
777
|
`).join('')}
|
|
718
778
|
</g>
|
|
779
|
+
<g class="galaxy-layer" aria-hidden="true">
|
|
780
|
+
${nebulae.map((nebula) => `
|
|
781
|
+
<circle class="nebula" cx="${nebula.x}" cy="${nebula.y}" r="${nebula.r}" fill="url(#nebula-grad-${nebula.id})" opacity="${nebula.opacity}"/>
|
|
782
|
+
`).join('')}
|
|
783
|
+
<g class="galaxy-spiral">
|
|
784
|
+
${galaxyDots.map((dot) => `<circle cx="${dot.x}" cy="${dot.y}" r="${dot.r}" fill="${dot.color}" opacity="${dot.opacity}"/>`).join('')}
|
|
785
|
+
</g>
|
|
786
|
+
<circle class="galaxy-core" cx="${GALAXY.cx}" cy="${GALAXY.cy}" r="120" fill="url(#galaxy-core-grad)"/>
|
|
787
|
+
</g>
|
|
719
788
|
<g id="graph-viewport">
|
|
720
789
|
<g class="edges">
|
|
721
790
|
${edges.map((edge, index) => `
|
|
@@ -734,6 +803,16 @@ function renderGraphCanvas(summary, copy) {
|
|
|
734
803
|
/>
|
|
735
804
|
`).join('')}
|
|
736
805
|
</g>
|
|
806
|
+
<g class="pulses" aria-hidden="true">
|
|
807
|
+
${pulses.map((pulse) => `
|
|
808
|
+
<g class="pulse-wrap" data-pulse-index="${pulse.index}">
|
|
809
|
+
<circle class="edge-pulse" r="2.6" fill="url(#pulse-grad)" opacity="0">
|
|
810
|
+
<animateMotion dur="${pulse.dur}s" begin="${pulse.begin}ms" repeatCount="indefinite" path="${escapeAttr(pulse.path)}"/>
|
|
811
|
+
<animate attributeName="opacity" values="0;0.95;0.95;0" keyTimes="0;0.12;0.85;1" dur="${pulse.dur}s" begin="${pulse.begin}ms" repeatCount="indefinite"/>
|
|
812
|
+
</circle>
|
|
813
|
+
</g>
|
|
814
|
+
`).join('')}
|
|
815
|
+
</g>
|
|
737
816
|
<g class="orbits" aria-hidden="true">
|
|
738
817
|
${orbitSystems.map((system) => `
|
|
739
818
|
<g class="orbit-system" data-parent="${escapeAttr(system.parentId)}" transform="translate(${system.x.toFixed(1)} ${system.y.toFixed(1)})">
|
|
@@ -1382,7 +1461,18 @@ function renderScript(harnesses, copy) {
|
|
|
1382
1461
|
};
|
|
1383
1462
|
const graphCanvas = document.querySelector('.graph-canvas');
|
|
1384
1463
|
const orbitSystems = Array.from(document.querySelectorAll('.orbit-system'));
|
|
1464
|
+
const pulseWraps = Array.from(document.querySelectorAll('.pulse-wrap'));
|
|
1385
1465
|
const defaultSelectedPanel = selectedPanel ? selectedPanel.innerHTML : '';
|
|
1466
|
+
function syncPulses() {
|
|
1467
|
+
const hasSelection = graphCanvas && graphCanvas.classList.contains('has-selection');
|
|
1468
|
+
pulseWraps.forEach((wrap) => {
|
|
1469
|
+
const edge = edges[Number(wrap.dataset.pulseIndex)];
|
|
1470
|
+
if (!edge) return;
|
|
1471
|
+
const hidden = edge.classList.contains('is-hidden') || edge.classList.contains('is-filtered-out');
|
|
1472
|
+
wrap.classList.toggle('is-hidden', hidden);
|
|
1473
|
+
wrap.classList.toggle('is-dimmed', Boolean(hasSelection && !edge.classList.contains('is-related')));
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1386
1476
|
function syncOrbits() {
|
|
1387
1477
|
const hasSelection = graphCanvas && graphCanvas.classList.contains('has-selection');
|
|
1388
1478
|
orbitSystems.forEach((system) => {
|
|
@@ -1392,6 +1482,7 @@ function renderScript(harnesses, copy) {
|
|
|
1392
1482
|
const related = parent && (parent.classList.contains('is-selected') || parent.classList.contains('is-related'));
|
|
1393
1483
|
system.classList.toggle('is-dimmed', Boolean(hasSelection && !related));
|
|
1394
1484
|
});
|
|
1485
|
+
syncPulses();
|
|
1395
1486
|
}
|
|
1396
1487
|
function clearSelection() {
|
|
1397
1488
|
nodes.forEach((item) => item.classList.remove('is-selected', 'is-related'));
|
|
@@ -1576,7 +1667,7 @@ function renderScript(harnesses, copy) {
|
|
|
1576
1667
|
suppressClick = false;
|
|
1577
1668
|
return;
|
|
1578
1669
|
}
|
|
1579
|
-
if (event.target.classList.contains('graph-bg') || event.target.closest('.starfield')) {
|
|
1670
|
+
if (event.target.classList.contains('graph-bg') || event.target.closest('.starfield') || event.target.closest('.galaxy-layer')) {
|
|
1580
1671
|
clearSelection();
|
|
1581
1672
|
if (selectedPanel && defaultSelectedPanel) selectedPanel.innerHTML = defaultSelectedPanel;
|
|
1582
1673
|
}
|
|
@@ -2265,6 +2356,39 @@ function renderStyles() {
|
|
|
2265
2356
|
to { opacity: 0.6; }
|
|
2266
2357
|
}
|
|
2267
2358
|
|
|
2359
|
+
.galaxy-layer { pointer-events: none; }
|
|
2360
|
+
|
|
2361
|
+
.nebula { mix-blend-mode: screen; }
|
|
2362
|
+
|
|
2363
|
+
.galaxy-spiral {
|
|
2364
|
+
transform-origin: 545px 340px;
|
|
2365
|
+
transform-box: view-box;
|
|
2366
|
+
animation: galaxy-rotate 420s linear infinite;
|
|
2367
|
+
mix-blend-mode: screen;
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
@keyframes galaxy-rotate {
|
|
2371
|
+
to { transform: rotate(360deg); }
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2374
|
+
.galaxy-core {
|
|
2375
|
+
mix-blend-mode: screen;
|
|
2376
|
+
animation: core-breathe 9s ease-in-out infinite alternate;
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
@keyframes core-breathe {
|
|
2380
|
+
from { opacity: 0.5; }
|
|
2381
|
+
to { opacity: 0.9; }
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
.pulse-wrap { transition: opacity 260ms ease; }
|
|
2385
|
+
.pulse-wrap.is-hidden { opacity: 0; }
|
|
2386
|
+
.pulse-wrap.is-dimmed { opacity: 0.08; }
|
|
2387
|
+
|
|
2388
|
+
.edge-pulse {
|
|
2389
|
+
filter: drop-shadow(0 0 4px rgba(157, 196, 255, 0.9));
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2268
2392
|
.orbit-ring {
|
|
2269
2393
|
fill: none;
|
|
2270
2394
|
stroke: var(--text-secondary);
|
|
@@ -2421,8 +2545,11 @@ function renderStyles() {
|
|
|
2421
2545
|
.graph-canvas text,
|
|
2422
2546
|
.orbit-spin,
|
|
2423
2547
|
.star-twinkle,
|
|
2548
|
+
.galaxy-spiral,
|
|
2549
|
+
.galaxy-core,
|
|
2424
2550
|
.page.is-active { animation: none; }
|
|
2425
2551
|
.graph-node { transition: none; }
|
|
2552
|
+
.pulses { display: none; }
|
|
2426
2553
|
}
|
|
2427
2554
|
|
|
2428
2555
|
.map-caption {
|