@principal-ai/file-city-react 0.5.25 → 0.5.26
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileCity3D.d.ts","sourceRoot":"","sources":["../../../src/components/FileCity3D/FileCity3D.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AAMjF,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,EAEb,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,OAAO,QAAQ,OAAO,CAAC;IAErB,UAAU,GAAG,CAAC;QAEZ,UAAU,iBAAkB,SAAQ,aAAa;SAAG;KACrD;CACF;AAGD,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;AAGrD,MAAM,WAAW,cAAc;IAC7B,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;CAC5B;AAED,gDAAgD;AAChD,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,aAAa,GACb,UAAU,GACV,MAAM,CAAC;AAGX,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,2CAA2C;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wCAAwC;AACxC,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,QAAQ,CAAC;AAErD,oFAAoF;AACpF,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,yDAAyD;AACzD,eAAO,MAAM,qBAAqB,EAAE,WAAW,EAS9C,CAAC;
|
|
1
|
+
{"version":3,"file":"FileCity3D.d.ts","sourceRoot":"","sources":["../../../src/components/FileCity3D/FileCity3D.tsx"],"names":[],"mappings":"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"}
|
|
@@ -472,55 +472,37 @@ function InstancedBuildings({ buildings, centerOffset, onHover, onClick, hovered
|
|
|
472
472
|
buildingIndex: d.index,
|
|
473
473
|
})), growProgress: growProgress, minHeight: minHeight, baseOffset: baseOffset, springDuration: springDuration, heightMultipliersRef: heightMultipliersRef })] }));
|
|
474
474
|
}
|
|
475
|
-
function AnimatedIcon({ x, z, targetHeight, iconSize, texture, opacity, growProgress,
|
|
475
|
+
function AnimatedIcon({ x, z, targetHeight, iconSize, texture, opacity, growProgress, }) {
|
|
476
476
|
const meshRef = useRef(null);
|
|
477
|
-
const startTimeRef = useRef(null);
|
|
478
477
|
const materialRef = useRef(null);
|
|
479
|
-
useFrame((
|
|
478
|
+
useFrame(() => {
|
|
480
479
|
if (!meshRef.current)
|
|
481
480
|
return;
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
}
|
|
485
|
-
const currentTime = clock.elapsedTime * 1000;
|
|
486
|
-
const animStartTime = startTimeRef.current ?? currentTime;
|
|
487
|
-
// Calculate per-icon animation progress
|
|
488
|
-
const elapsed = currentTime - animStartTime - staggerDelayMs;
|
|
489
|
-
let animProgress = growProgress;
|
|
490
|
-
if (growProgress > 0 && elapsed >= 0) {
|
|
491
|
-
const t = Math.min(elapsed / springDuration, 1);
|
|
492
|
-
const eased = 1 - Math.pow(1 - t, 3);
|
|
493
|
-
animProgress = eased * growProgress;
|
|
494
|
-
}
|
|
495
|
-
else if (growProgress > 0 && elapsed < 0) {
|
|
496
|
-
animProgress = 0;
|
|
497
|
-
}
|
|
481
|
+
// Icons track the global growProgress directly (no stagger)
|
|
482
|
+
// This keeps them in sync with the building heights
|
|
498
483
|
const minHeight = 0.3;
|
|
499
484
|
const baseOffset = 0.2;
|
|
500
|
-
const height =
|
|
485
|
+
const height = growProgress * targetHeight + minHeight;
|
|
501
486
|
const buildingTop = height + baseOffset;
|
|
502
|
-
// When flat (
|
|
503
|
-
// When grown (
|
|
504
|
-
const flatY = minHeight + baseOffset + 0.
|
|
505
|
-
const grownY = buildingTop + 0.
|
|
506
|
-
const yPosition = flatY + (grownY - flatY) *
|
|
487
|
+
// When flat (growProgress=0): icon lies flat at ground level
|
|
488
|
+
// When grown (growProgress=1): icon lies flat above building roof
|
|
489
|
+
const flatY = minHeight + baseOffset + 0.5;
|
|
490
|
+
const grownY = buildingTop + 0.5;
|
|
491
|
+
const yPosition = flatY + (grownY - flatY) * growProgress;
|
|
507
492
|
meshRef.current.position.y = yPosition;
|
|
508
493
|
// Keep icon flat (facing up) at all times
|
|
509
494
|
meshRef.current.rotation.x = -Math.PI / 2;
|
|
510
495
|
if (materialRef.current) {
|
|
511
|
-
|
|
512
|
-
const minOpacity = 0.8;
|
|
513
|
-
const effectiveOpacity = minOpacity + (1 - minOpacity) * animProgress;
|
|
514
|
-
materialRef.current.opacity = opacity * effectiveOpacity;
|
|
496
|
+
materialRef.current.opacity = opacity;
|
|
515
497
|
}
|
|
516
498
|
});
|
|
517
499
|
return (_jsxs("mesh", { ref: meshRef, position: [x, 0, z], scale: [iconSize, iconSize, 1], raycast: () => null, children: [_jsx("planeGeometry", { args: [1, 1] }), _jsx("meshBasicMaterial", { ref: materialRef, map: texture, transparent: true, opacity: 0.8, depthTest: true, depthWrite: false, side: THREE.DoubleSide })] }));
|
|
518
500
|
}
|
|
519
|
-
function BuildingIcons({ buildings, centerOffset, growProgress, heightScaling, linearScale, flatPatterns, highlightLayers, isolationMode, hasActiveHighlights,
|
|
501
|
+
function BuildingIcons({ buildings, centerOffset, growProgress, heightScaling, linearScale, flatPatterns, highlightLayers, isolationMode, hasActiveHighlights, }) {
|
|
520
502
|
// Pre-compute buildings with icons
|
|
521
503
|
const buildingsWithIcons = useMemo(() => {
|
|
522
504
|
return buildings
|
|
523
|
-
.map((building
|
|
505
|
+
.map((building) => {
|
|
524
506
|
const config = getConfigForFile(building);
|
|
525
507
|
if (!config.icon)
|
|
526
508
|
return null;
|
|
@@ -529,14 +511,13 @@ function BuildingIcons({ buildings, centerOffset, growProgress, heightScaling, l
|
|
|
529
511
|
const shouldDim = hasActiveHighlights && !isHighlighted;
|
|
530
512
|
const shouldHide = shouldDim && isolationMode === 'hide';
|
|
531
513
|
const shouldCollapse = shouldDim && isolationMode === 'collapse';
|
|
532
|
-
|
|
514
|
+
// Hide icons for buildings that are hidden or collapsed
|
|
515
|
+
if (shouldHide || shouldCollapse)
|
|
533
516
|
return null;
|
|
534
517
|
const fullHeight = calculateBuildingHeight(building, heightScaling, linearScale, flatPatterns);
|
|
535
|
-
const targetHeight =
|
|
518
|
+
const targetHeight = fullHeight;
|
|
536
519
|
const x = building.position.x - centerOffset.x;
|
|
537
520
|
const z = building.position.z - centerOffset.z;
|
|
538
|
-
const staggerIndex = staggerIndices[index] ?? index;
|
|
539
|
-
const staggerDelayMs = staggerDelay * staggerIndex;
|
|
540
521
|
return {
|
|
541
522
|
building,
|
|
542
523
|
config,
|
|
@@ -544,7 +525,6 @@ function BuildingIcons({ buildings, centerOffset, growProgress, heightScaling, l
|
|
|
544
525
|
z,
|
|
545
526
|
targetHeight,
|
|
546
527
|
shouldDim,
|
|
547
|
-
staggerDelayMs,
|
|
548
528
|
};
|
|
549
529
|
})
|
|
550
530
|
.filter(Boolean);
|
|
@@ -557,11 +537,9 @@ function BuildingIcons({ buildings, centerOffset, growProgress, heightScaling, l
|
|
|
557
537
|
heightScaling,
|
|
558
538
|
linearScale,
|
|
559
539
|
flatPatterns,
|
|
560
|
-
staggerIndices,
|
|
561
|
-
staggerDelay,
|
|
562
540
|
]);
|
|
563
541
|
// Icons are now always rendered (flat or grown)
|
|
564
|
-
return (_jsx(_Fragment, { children: buildingsWithIcons.map(({ building, config, x, z, targetHeight, shouldDim
|
|
542
|
+
return (_jsx(_Fragment, { children: buildingsWithIcons.map(({ building, config, x, z, targetHeight, shouldDim }) => {
|
|
565
543
|
const icon = config.icon;
|
|
566
544
|
const texture = getIconTexture(icon.name, icon.color || '#ffffff');
|
|
567
545
|
if (!texture)
|
|
@@ -571,7 +549,7 @@ function BuildingIcons({ buildings, centerOffset, growProgress, heightScaling, l
|
|
|
571
549
|
const minDimension = Math.min(width, depth);
|
|
572
550
|
const iconSize = minDimension * (icon.size || 0.6) * 1.7;
|
|
573
551
|
const opacity = shouldDim && isolationMode === 'transparent' ? 0.3 : 1;
|
|
574
|
-
return (_jsx(AnimatedIcon, { x: x, z: z, targetHeight: targetHeight, iconSize: iconSize, texture: texture, opacity: opacity, growProgress: growProgress
|
|
552
|
+
return (_jsx(AnimatedIcon, { x: x, z: z, targetHeight: targetHeight, iconSize: iconSize, texture: texture, opacity: opacity, growProgress: growProgress }, building.path));
|
|
575
553
|
}) }));
|
|
576
554
|
}
|
|
577
555
|
function DistrictFloor({ district, centerOffset, highlightColor, growProgress }) {
|
|
@@ -1350,7 +1328,7 @@ function CityScene({ cityData, onBuildingHover, onBuildingClick, hoveredBuilding
|
|
|
1350
1328
|
// Focus color takes priority, then highlight layer color
|
|
1351
1329
|
const districtColor = (isFocused && buildingFocusColor) ? buildingFocusColor : highlightLayerColor;
|
|
1352
1330
|
return (_jsx(DistrictFloor, { district: district, centerOffset: centerOffset, opacity: 1, highlightColor: districtColor, growProgress: growProgress }, district.path));
|
|
1353
|
-
}), _jsx(InstancedBuildings, { buildings: cityData.buildings, centerOffset: centerOffset, onHover: onBuildingHover, onClick: onBuildingClick, hoveredIndex: hoveredIndex, selectedIndex: selectedIndex, growProgress: growProgress, animationConfig: animationConfig, heightScaling: heightScaling, linearScale: linearScale, flatPatterns: flatPatterns, staggerIndices: staggerIndices, focusDirectory: buildingFocusDirectory, highlightLayers: highlightLayers, isolationMode: isolationMode }), _jsx(BuildingIcons, { buildings: cityData.buildings, centerOffset: centerOffset, growProgress: growProgress, heightScaling: heightScaling, linearScale: linearScale, flatPatterns: flatPatterns, highlightLayers: highlightLayers, isolationMode: isolationMode, hasActiveHighlights: activeHighlights
|
|
1331
|
+
}), _jsx(InstancedBuildings, { buildings: cityData.buildings, centerOffset: centerOffset, onHover: onBuildingHover, onClick: onBuildingClick, hoveredIndex: hoveredIndex, selectedIndex: selectedIndex, growProgress: growProgress, animationConfig: animationConfig, heightScaling: heightScaling, linearScale: linearScale, flatPatterns: flatPatterns, staggerIndices: staggerIndices, focusDirectory: buildingFocusDirectory, highlightLayers: highlightLayers, isolationMode: isolationMode }), _jsx(BuildingIcons, { buildings: cityData.buildings, centerOffset: centerOffset, growProgress: growProgress, heightScaling: heightScaling, linearScale: linearScale, flatPatterns: flatPatterns, highlightLayers: highlightLayers, isolationMode: isolationMode, hasActiveHighlights: activeHighlights })] }));
|
|
1354
1332
|
}
|
|
1355
1333
|
/**
|
|
1356
1334
|
* FileCity3D - 3D visualization of codebase structure
|
package/package.json
CHANGED
|
@@ -769,9 +769,6 @@ interface BuildingIconsProps {
|
|
|
769
769
|
highlightLayers: HighlightLayer[];
|
|
770
770
|
isolationMode: IsolationMode;
|
|
771
771
|
hasActiveHighlights: boolean;
|
|
772
|
-
staggerIndices: number[];
|
|
773
|
-
springDuration: number;
|
|
774
|
-
staggerDelay: number;
|
|
775
772
|
}
|
|
776
773
|
|
|
777
774
|
// Individual animated icon component
|
|
@@ -783,8 +780,6 @@ interface AnimatedIconProps {
|
|
|
783
780
|
texture: THREE.Texture;
|
|
784
781
|
opacity: number;
|
|
785
782
|
growProgress: number;
|
|
786
|
-
staggerDelayMs: number;
|
|
787
|
-
springDuration: number;
|
|
788
783
|
}
|
|
789
784
|
|
|
790
785
|
function AnimatedIcon({
|
|
@@ -795,45 +790,25 @@ function AnimatedIcon({
|
|
|
795
790
|
texture,
|
|
796
791
|
opacity,
|
|
797
792
|
growProgress,
|
|
798
|
-
staggerDelayMs,
|
|
799
|
-
springDuration,
|
|
800
793
|
}: AnimatedIconProps) {
|
|
801
794
|
const meshRef = useRef<THREE.Mesh>(null);
|
|
802
|
-
const startTimeRef = useRef<number | null>(null);
|
|
803
795
|
const materialRef = useRef<THREE.MeshBasicMaterial>(null);
|
|
804
796
|
|
|
805
|
-
useFrame((
|
|
797
|
+
useFrame(() => {
|
|
806
798
|
if (!meshRef.current) return;
|
|
807
799
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
const currentTime = clock.elapsedTime * 1000;
|
|
813
|
-
const animStartTime = startTimeRef.current ?? currentTime;
|
|
814
|
-
|
|
815
|
-
// Calculate per-icon animation progress
|
|
816
|
-
const elapsed = currentTime - animStartTime - staggerDelayMs;
|
|
817
|
-
let animProgress = growProgress;
|
|
818
|
-
|
|
819
|
-
if (growProgress > 0 && elapsed >= 0) {
|
|
820
|
-
const t = Math.min(elapsed / springDuration, 1);
|
|
821
|
-
const eased = 1 - Math.pow(1 - t, 3);
|
|
822
|
-
animProgress = eased * growProgress;
|
|
823
|
-
} else if (growProgress > 0 && elapsed < 0) {
|
|
824
|
-
animProgress = 0;
|
|
825
|
-
}
|
|
826
|
-
|
|
800
|
+
// Icons track the global growProgress directly (no stagger)
|
|
801
|
+
// This keeps them in sync with the building heights
|
|
827
802
|
const minHeight = 0.3;
|
|
828
803
|
const baseOffset = 0.2;
|
|
829
|
-
const height =
|
|
804
|
+
const height = growProgress * targetHeight + minHeight;
|
|
830
805
|
const buildingTop = height + baseOffset;
|
|
831
806
|
|
|
832
|
-
// When flat (
|
|
833
|
-
// When grown (
|
|
834
|
-
const flatY = minHeight + baseOffset + 0.
|
|
835
|
-
const grownY = buildingTop + 0.
|
|
836
|
-
const yPosition = flatY + (grownY - flatY) *
|
|
807
|
+
// When flat (growProgress=0): icon lies flat at ground level
|
|
808
|
+
// When grown (growProgress=1): icon lies flat above building roof
|
|
809
|
+
const flatY = minHeight + baseOffset + 0.5;
|
|
810
|
+
const grownY = buildingTop + 0.5;
|
|
811
|
+
const yPosition = flatY + (grownY - flatY) * growProgress;
|
|
837
812
|
|
|
838
813
|
meshRef.current.position.y = yPosition;
|
|
839
814
|
|
|
@@ -841,10 +816,7 @@ function AnimatedIcon({
|
|
|
841
816
|
meshRef.current.rotation.x = -Math.PI / 2;
|
|
842
817
|
|
|
843
818
|
if (materialRef.current) {
|
|
844
|
-
|
|
845
|
-
const minOpacity = 0.8;
|
|
846
|
-
const effectiveOpacity = minOpacity + (1 - minOpacity) * animProgress;
|
|
847
|
-
materialRef.current.opacity = opacity * effectiveOpacity;
|
|
819
|
+
materialRef.current.opacity = opacity;
|
|
848
820
|
}
|
|
849
821
|
});
|
|
850
822
|
|
|
@@ -879,14 +851,11 @@ function BuildingIcons({
|
|
|
879
851
|
highlightLayers,
|
|
880
852
|
isolationMode,
|
|
881
853
|
hasActiveHighlights,
|
|
882
|
-
staggerIndices,
|
|
883
|
-
springDuration,
|
|
884
|
-
staggerDelay,
|
|
885
854
|
}: BuildingIconsProps) {
|
|
886
855
|
// Pre-compute buildings with icons
|
|
887
856
|
const buildingsWithIcons = useMemo(() => {
|
|
888
857
|
return buildings
|
|
889
|
-
.map((building
|
|
858
|
+
.map((building) => {
|
|
890
859
|
const config = getConfigForFile(building);
|
|
891
860
|
if (!config.icon) return null;
|
|
892
861
|
|
|
@@ -896,17 +865,15 @@ function BuildingIcons({
|
|
|
896
865
|
const shouldHide = shouldDim && isolationMode === 'hide';
|
|
897
866
|
const shouldCollapse = shouldDim && isolationMode === 'collapse';
|
|
898
867
|
|
|
899
|
-
|
|
868
|
+
// Hide icons for buildings that are hidden or collapsed
|
|
869
|
+
if (shouldHide || shouldCollapse) return null;
|
|
900
870
|
|
|
901
871
|
const fullHeight = calculateBuildingHeight(building, heightScaling, linearScale, flatPatterns);
|
|
902
|
-
const targetHeight =
|
|
872
|
+
const targetHeight = fullHeight;
|
|
903
873
|
|
|
904
874
|
const x = building.position.x - centerOffset.x;
|
|
905
875
|
const z = building.position.z - centerOffset.z;
|
|
906
876
|
|
|
907
|
-
const staggerIndex = staggerIndices[index] ?? index;
|
|
908
|
-
const staggerDelayMs = staggerDelay * staggerIndex;
|
|
909
|
-
|
|
910
877
|
return {
|
|
911
878
|
building,
|
|
912
879
|
config,
|
|
@@ -914,7 +881,6 @@ function BuildingIcons({
|
|
|
914
881
|
z,
|
|
915
882
|
targetHeight,
|
|
916
883
|
shouldDim,
|
|
917
|
-
staggerDelayMs,
|
|
918
884
|
};
|
|
919
885
|
})
|
|
920
886
|
.filter(Boolean) as Array<{
|
|
@@ -924,7 +890,6 @@ function BuildingIcons({
|
|
|
924
890
|
z: number;
|
|
925
891
|
targetHeight: number;
|
|
926
892
|
shouldDim: boolean;
|
|
927
|
-
staggerDelayMs: number;
|
|
928
893
|
}>;
|
|
929
894
|
}, [
|
|
930
895
|
buildings,
|
|
@@ -935,15 +900,13 @@ function BuildingIcons({
|
|
|
935
900
|
heightScaling,
|
|
936
901
|
linearScale,
|
|
937
902
|
flatPatterns,
|
|
938
|
-
staggerIndices,
|
|
939
|
-
staggerDelay,
|
|
940
903
|
]);
|
|
941
904
|
|
|
942
905
|
// Icons are now always rendered (flat or grown)
|
|
943
906
|
return (
|
|
944
907
|
<>
|
|
945
908
|
{buildingsWithIcons.map(
|
|
946
|
-
({ building, config, x, z, targetHeight, shouldDim
|
|
909
|
+
({ building, config, x, z, targetHeight, shouldDim }) => {
|
|
947
910
|
const icon = config.icon!;
|
|
948
911
|
const texture = getIconTexture(icon.name, icon.color || '#ffffff');
|
|
949
912
|
if (!texture) return null;
|
|
@@ -965,8 +928,6 @@ function BuildingIcons({
|
|
|
965
928
|
texture={texture}
|
|
966
929
|
opacity={opacity}
|
|
967
930
|
growProgress={growProgress}
|
|
968
|
-
staggerDelayMs={staggerDelayMs}
|
|
969
|
-
springDuration={springDuration}
|
|
970
931
|
/>
|
|
971
932
|
);
|
|
972
933
|
},
|
|
@@ -2135,9 +2096,6 @@ function CityScene({
|
|
|
2135
2096
|
highlightLayers={highlightLayers}
|
|
2136
2097
|
isolationMode={isolationMode}
|
|
2137
2098
|
hasActiveHighlights={activeHighlights}
|
|
2138
|
-
staggerIndices={staggerIndices}
|
|
2139
|
-
springDuration={springDuration}
|
|
2140
|
-
staggerDelay={animationConfig.staggerDelay || 15}
|
|
2141
2099
|
/>
|
|
2142
2100
|
</>
|
|
2143
2101
|
);
|