@principal-ai/file-city-react 0.5.17 → 0.5.18

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":"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"}
1
+ {"version":3,"file":"FileCity3D.d.ts","sourceRoot":"","sources":["../../../src/components/FileCity3D/FileCity3D.tsx"],"names":[],"mappings":"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"}
@@ -439,11 +439,11 @@ function InstancedBuildings({ buildings, centerOffset, onHover, onClick, hovered
439
439
  })), growProgress: growProgress, minHeight: minHeight, baseOffset: baseOffset, springDuration: springDuration, heightMultipliersRef: heightMultipliersRef })] }));
440
440
  }
441
441
  function AnimatedIcon({ x, z, targetHeight, iconSize, texture, opacity, growProgress, staggerDelayMs, springDuration, }) {
442
- const spriteRef = useRef(null);
442
+ const meshRef = useRef(null);
443
443
  const startTimeRef = useRef(null);
444
444
  const materialRef = useRef(null);
445
445
  useFrame(({ clock }) => {
446
- if (!spriteRef.current)
446
+ if (!meshRef.current)
447
447
  return;
448
448
  if (startTimeRef.current === null && growProgress > 0) {
449
449
  startTimeRef.current = clock.elapsedTime * 1000;
@@ -465,13 +465,26 @@ function AnimatedIcon({ x, z, targetHeight, iconSize, texture, opacity, growProg
465
465
  const baseOffset = 0.2;
466
466
  const height = animProgress * targetHeight + minHeight;
467
467
  const buildingTop = height + baseOffset;
468
- const yPosition = buildingTop + iconSize / 2 + 2;
469
- spriteRef.current.position.y = yPosition;
468
+ // When flat (animProgress=0): icon lies flat at ground level
469
+ // When grown (animProgress=1): icon floats above building
470
+ const flatY = minHeight + baseOffset + 0.5;
471
+ const grownY = buildingTop + iconSize / 2 + 2;
472
+ const yPosition = flatY + (grownY - flatY) * animProgress;
473
+ meshRef.current.position.y = yPosition;
474
+ // Rotate from flat (facing up) to upright (facing camera-ish)
475
+ // Flat: -Math.PI / 2 (facing up)
476
+ // Grown: 0 (facing forward)
477
+ const flatRotationX = -Math.PI / 2;
478
+ const grownRotationX = 0;
479
+ meshRef.current.rotation.x = flatRotationX + (grownRotationX - flatRotationX) * animProgress;
470
480
  if (materialRef.current) {
471
- materialRef.current.opacity = opacity * animProgress;
481
+ // Show icons even when flat, fade out only slightly
482
+ const minOpacity = 0.8;
483
+ const effectiveOpacity = minOpacity + (1 - minOpacity) * animProgress;
484
+ materialRef.current.opacity = opacity * effectiveOpacity;
472
485
  }
473
486
  });
474
- return (_jsx("sprite", { ref: spriteRef, position: [x, 0, z], scale: [iconSize, iconSize, 1], raycast: () => null, children: _jsx("spriteMaterial", { ref: materialRef, map: texture, transparent: true, opacity: 0, depthTest: true, depthWrite: false }) }));
487
+ 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 })] }));
475
488
  }
476
489
  function BuildingIcons({ buildings, centerOffset, growProgress, heightScaling, linearScale, highlightLayers, isolationMode, hasActiveHighlights, staggerIndices, springDuration, staggerDelay, }) {
477
490
  // Pre-compute buildings with icons
@@ -516,9 +529,7 @@ function BuildingIcons({ buildings, centerOffset, growProgress, heightScaling, l
516
529
  staggerIndices,
517
530
  staggerDelay,
518
531
  ]);
519
- // Don't render if no progress yet
520
- if (growProgress < 0.1)
521
- return null;
532
+ // Icons are now always rendered (flat or grown)
522
533
  return (_jsx(_Fragment, { children: buildingsWithIcons.map(({ building, config, x, z, targetHeight, shouldDim, staggerDelayMs }) => {
523
534
  const icon = config.icon;
524
535
  const texture = getIconTexture(icon.name, icon.color || '#ffffff');
@@ -526,14 +537,14 @@ function BuildingIcons({ buildings, centerOffset, growProgress, heightScaling, l
526
537
  return null;
527
538
  // Icon size based on building dimensions
528
539
  const [width] = building.dimensions;
529
- const baseSize = Math.max(width * 0.8, 6);
540
+ const baseSize = Math.max(width * 1.2, 8);
530
541
  const heightBoost = Math.min(targetHeight / 20, 3);
531
542
  const iconSize = (baseSize + heightBoost) * (icon.size || 1);
532
543
  const opacity = shouldDim && isolationMode === 'transparent' ? 0.3 : 1;
533
544
  return (_jsx(AnimatedIcon, { x: x, z: z, targetHeight: targetHeight, iconSize: iconSize, texture: texture, opacity: opacity, growProgress: growProgress, staggerDelayMs: staggerDelayMs, springDuration: springDuration }, building.path));
534
545
  }) }));
535
546
  }
536
- function DistrictFloor({ district, centerOffset, highlightColor }) {
547
+ function DistrictFloor({ district, centerOffset, highlightColor, growProgress }) {
537
548
  const { worldBounds } = district;
538
549
  const width = worldBounds.maxX - worldBounds.minX;
539
550
  const depth = worldBounds.maxZ - worldBounds.minZ;
@@ -545,7 +556,19 @@ function DistrictFloor({ district, centerOffset, highlightColor }) {
545
556
  const borderColor = highlightColor || '#475569';
546
557
  const lineWidth = highlightColor ? 3 : 1;
547
558
  const labelColor = highlightColor || '#cbd5e1';
548
- return (_jsxs("group", { position: [centerX, 0, centerZ], children: [_jsxs("lineSegments", { rotation: [-Math.PI / 2, 0, 0], position: [0, floorY, 0], renderOrder: -1, children: [_jsx("edgesGeometry", { args: [new THREE.PlaneGeometry(width, depth)], attach: "geometry" }), _jsx("lineBasicMaterial", { color: borderColor, linewidth: lineWidth, depthWrite: false })] }), highlightColor && (_jsxs("mesh", { rotation: [-Math.PI / 2, 0, 0], position: [0, floorY - 0.1, 0], renderOrder: -2, children: [_jsx("planeGeometry", { args: [width, depth] }), _jsx("meshBasicMaterial", { color: highlightColor, transparent: true, opacity: 0.15, depthWrite: false })] })), district.label && (_jsx(Text, { position: [0, 1.5, depth / 2 + 2], rotation: [-Math.PI / 6, 0, 0], fontSize: Math.min(3, width / 6), color: labelColor, anchorX: "center", anchorY: "middle", outlineWidth: 0.1, outlineColor: "#0f172a", children: dirName }))] }));
559
+ // Interpolate text rotation and position based on growProgress
560
+ // Flat: -Math.PI / 2 (facing up), positioned at center of district
561
+ // Grown: -Math.PI / 6 (angled), positioned at edge of district
562
+ const flatRotationX = -Math.PI / 2;
563
+ const grownRotationX = -Math.PI / 6;
564
+ const textRotationX = flatRotationX + (grownRotationX - flatRotationX) * growProgress;
565
+ const flatY = 0.5;
566
+ const grownY = 1.5;
567
+ const textY = flatY + (grownY - flatY) * growProgress;
568
+ const flatZ = 0; // Center of district when flat
569
+ const grownZ = depth / 2 + 2; // Edge of district when grown
570
+ const textZ = flatZ + (grownZ - flatZ) * growProgress;
571
+ return (_jsxs("group", { position: [centerX, 0, centerZ], children: [_jsxs("lineSegments", { rotation: [-Math.PI / 2, 0, 0], position: [0, floorY, 0], renderOrder: -1, children: [_jsx("edgesGeometry", { args: [new THREE.PlaneGeometry(width, depth)], attach: "geometry" }), _jsx("lineBasicMaterial", { color: borderColor, linewidth: lineWidth, depthWrite: false })] }), highlightColor && (_jsxs("mesh", { rotation: [-Math.PI / 2, 0, 0], position: [0, floorY - 0.1, 0], renderOrder: -2, children: [_jsx("planeGeometry", { args: [width, depth] }), _jsx("meshBasicMaterial", { color: highlightColor, transparent: true, opacity: 0.15, depthWrite: false })] })), district.label && (_jsx(Text, { position: [0, textY, textZ], rotation: [textRotationX, 0, 0], fontSize: Math.min(3, width / 6), color: labelColor, anchorX: "center", anchorY: "middle", outlineWidth: 0.1, outlineColor: "#0f172a", children: dirName }))] }));
549
572
  }
550
573
  let cameraApi = null;
551
574
  export function resetCamera() {
@@ -1297,7 +1320,7 @@ function CityScene({ cityData, onBuildingHover, onBuildingClick, hoveredBuilding
1297
1320
  // Use buildingFocusColor (synced with animation) instead of focusColor prop
1298
1321
  // Focus color takes priority, then highlight layer color
1299
1322
  const districtColor = (isFocused && buildingFocusColor) ? buildingFocusColor : highlightLayerColor;
1300
- return (_jsx(DistrictFloor, { district: district, centerOffset: centerOffset, opacity: 1, highlightColor: districtColor }, district.path));
1323
+ return (_jsx(DistrictFloor, { district: district, centerOffset: centerOffset, opacity: 1, highlightColor: districtColor, growProgress: growProgress }, district.path));
1301
1324
  }), _jsx(InstancedBuildings, { buildings: cityData.buildings, centerOffset: centerOffset, onHover: onBuildingHover, onClick: onBuildingClick, hoveredIndex: hoveredIndex, selectedIndex: selectedIndex, growProgress: growProgress, animationConfig: animationConfig, heightScaling: heightScaling, linearScale: linearScale, staggerIndices: staggerIndices, focusDirectory: buildingFocusDirectory, highlightLayers: highlightLayers, isolationMode: isolationMode }), _jsx(BuildingIcons, { buildings: cityData.buildings, centerOffset: centerOffset, growProgress: growProgress, heightScaling: heightScaling, linearScale: linearScale, highlightLayers: highlightLayers, isolationMode: isolationMode, hasActiveHighlights: activeHighlights, staggerIndices: staggerIndices, springDuration: springDuration, staggerDelay: animationConfig.staggerDelay || 15 })] }));
1302
1325
  }
1303
1326
  /**
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * FileCity3D - 3D visualization component
3
3
  */
4
- export { FileCity3D, resetCamera, moveCameraTo, setCameraTarget, getCameraTarget, rotateCameraTo, rotateCameraBy, tiltCameraTo, tiltCameraBy, getCameraPosition, getCameraAngle, getCameraTilt } from './FileCity3D';
5
- export type { FileCity3DProps, AnimationConfig, HighlightLayer, HighlightItem, IsolationMode, HeightScaling, CityData, CityBuilding, CityDistrict, RotateOptions, } from './FileCity3D';
4
+ export { FileCity3D, resetCamera, getCameraAngle, getCameraTarget, getCameraTilt, rotateCameraTo, rotateCameraBy, tiltCameraTo, tiltCameraBy, moveCameraTo, setCameraTarget, } from './FileCity3D';
5
+ export type { FileCity3DProps, AnimationConfig, HighlightLayer, HighlightItem, IsolationMode, HeightScaling, CityData, CityBuilding, CityDistrict, } from './FileCity3D';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FileCity3D/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACrN,YAAY,EACV,eAAe,EACf,eAAe,EACf,cAAc,EACd,aAAa,EACb,aAAa,EACb,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FileCity3D/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,UAAU,EACV,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,cAAc,EACd,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,eAAe,EACf,eAAe,EACf,cAAc,EACd,aAAa,EACb,aAAa,EACb,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,YAAY,GACb,MAAM,cAAc,CAAC"}
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * FileCity3D - 3D visualization component
3
3
  */
4
- export { FileCity3D, resetCamera, moveCameraTo, setCameraTarget, getCameraTarget, rotateCameraTo, rotateCameraBy, tiltCameraTo, tiltCameraBy, getCameraPosition, getCameraAngle, getCameraTilt } from './FileCity3D';
4
+ export { FileCity3D, resetCamera, getCameraAngle, getCameraTarget, getCameraTilt, rotateCameraTo, rotateCameraBy, tiltCameraTo, tiltCameraBy, moveCameraTo, setCameraTarget, } from './FileCity3D';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principal-ai/file-city-react",
3
- "version": "0.5.17",
3
+ "version": "0.5.18",
4
4
  "type": "module",
5
5
  "description": "React components for File City visualization",
6
6
  "main": "dist/index.js",
@@ -745,12 +745,12 @@ function AnimatedIcon({
745
745
  staggerDelayMs,
746
746
  springDuration,
747
747
  }: AnimatedIconProps) {
748
- const spriteRef = useRef<THREE.Sprite>(null);
748
+ const meshRef = useRef<THREE.Mesh>(null);
749
749
  const startTimeRef = useRef<number | null>(null);
750
- const materialRef = useRef<THREE.SpriteMaterial>(null);
750
+ const materialRef = useRef<THREE.MeshBasicMaterial>(null);
751
751
 
752
752
  useFrame(({ clock }) => {
753
- if (!spriteRef.current) return;
753
+ if (!meshRef.current) return;
754
754
 
755
755
  if (startTimeRef.current === null && growProgress > 0) {
756
756
  startTimeRef.current = clock.elapsedTime * 1000;
@@ -775,31 +775,48 @@ function AnimatedIcon({
775
775
  const baseOffset = 0.2;
776
776
  const height = animProgress * targetHeight + minHeight;
777
777
  const buildingTop = height + baseOffset;
778
- const yPosition = buildingTop + iconSize / 2 + 2;
779
778
 
780
- spriteRef.current.position.y = yPosition;
779
+ // When flat (animProgress=0): icon lies flat at ground level
780
+ // When grown (animProgress=1): icon floats above building
781
+ const flatY = minHeight + baseOffset + 0.5;
782
+ const grownY = buildingTop + iconSize / 2 + 2;
783
+ const yPosition = flatY + (grownY - flatY) * animProgress;
784
+
785
+ meshRef.current.position.y = yPosition;
786
+
787
+ // Rotate from flat (facing up) to upright (facing camera-ish)
788
+ // Flat: -Math.PI / 2 (facing up)
789
+ // Grown: 0 (facing forward)
790
+ const flatRotationX = -Math.PI / 2;
791
+ const grownRotationX = 0;
792
+ meshRef.current.rotation.x = flatRotationX + (grownRotationX - flatRotationX) * animProgress;
781
793
 
782
794
  if (materialRef.current) {
783
- materialRef.current.opacity = opacity * animProgress;
795
+ // Show icons even when flat, fade out only slightly
796
+ const minOpacity = 0.8;
797
+ const effectiveOpacity = minOpacity + (1 - minOpacity) * animProgress;
798
+ materialRef.current.opacity = opacity * effectiveOpacity;
784
799
  }
785
800
  });
786
801
 
787
802
  return (
788
- <sprite
789
- ref={spriteRef}
803
+ <mesh
804
+ ref={meshRef}
790
805
  position={[x, 0, z]}
791
806
  scale={[iconSize, iconSize, 1]}
792
807
  raycast={() => null}
793
808
  >
794
- <spriteMaterial
809
+ <planeGeometry args={[1, 1]} />
810
+ <meshBasicMaterial
795
811
  ref={materialRef}
796
812
  map={texture}
797
813
  transparent
798
- opacity={0}
814
+ opacity={0.8}
799
815
  depthTest={true}
800
816
  depthWrite={false}
817
+ side={THREE.DoubleSide}
801
818
  />
802
- </sprite>
819
+ </mesh>
803
820
  );
804
821
  }
805
822
 
@@ -871,9 +888,7 @@ function BuildingIcons({
871
888
  staggerDelay,
872
889
  ]);
873
890
 
874
- // Don't render if no progress yet
875
- if (growProgress < 0.1) return null;
876
-
891
+ // Icons are now always rendered (flat or grown)
877
892
  return (
878
893
  <>
879
894
  {buildingsWithIcons.map(
@@ -884,7 +899,7 @@ function BuildingIcons({
884
899
 
885
900
  // Icon size based on building dimensions
886
901
  const [width] = building.dimensions;
887
- const baseSize = Math.max(width * 0.8, 6);
902
+ const baseSize = Math.max(width * 1.2, 8);
888
903
  const heightBoost = Math.min(targetHeight / 20, 3);
889
904
  const iconSize = (baseSize + heightBoost) * (icon.size || 1);
890
905
 
@@ -916,9 +931,10 @@ interface DistrictFloorProps {
916
931
  centerOffset: { x: number; z: number };
917
932
  opacity: number;
918
933
  highlightColor?: string | null;
934
+ growProgress: number;
919
935
  }
920
936
 
921
- function DistrictFloor({ district, centerOffset, highlightColor }: DistrictFloorProps) {
937
+ function DistrictFloor({ district, centerOffset, highlightColor, growProgress }: DistrictFloorProps) {
922
938
  const { worldBounds } = district;
923
939
  const width = worldBounds.maxX - worldBounds.minX;
924
940
  const depth = worldBounds.maxZ - worldBounds.minZ;
@@ -934,6 +950,21 @@ function DistrictFloor({ district, centerOffset, highlightColor }: DistrictFloor
934
950
  const lineWidth = highlightColor ? 3 : 1;
935
951
  const labelColor = highlightColor || '#cbd5e1';
936
952
 
953
+ // Interpolate text rotation and position based on growProgress
954
+ // Flat: -Math.PI / 2 (facing up), positioned at center of district
955
+ // Grown: -Math.PI / 6 (angled), positioned at edge of district
956
+ const flatRotationX = -Math.PI / 2;
957
+ const grownRotationX = -Math.PI / 6;
958
+ const textRotationX = flatRotationX + (grownRotationX - flatRotationX) * growProgress;
959
+
960
+ const flatY = 0.5;
961
+ const grownY = 1.5;
962
+ const textY = flatY + (grownY - flatY) * growProgress;
963
+
964
+ const flatZ = 0; // Center of district when flat
965
+ const grownZ = depth / 2 + 2; // Edge of district when grown
966
+ const textZ = flatZ + (grownZ - flatZ) * growProgress;
967
+
937
968
  return (
938
969
  <group position={[centerX, 0, centerZ]}>
939
970
  {/* Border outline */}
@@ -952,8 +983,8 @@ function DistrictFloor({ district, centerOffset, highlightColor }: DistrictFloor
952
983
 
953
984
  {district.label && (
954
985
  <Text
955
- position={[0, 1.5, depth / 2 + 2]}
956
- rotation={[-Math.PI / 6, 0, 0]}
986
+ position={[0, textY, textZ]}
987
+ rotation={[textRotationX, 0, 0]}
957
988
  fontSize={Math.min(3, width / 6)}
958
989
  color={labelColor}
959
990
  anchorX="center"
@@ -2018,6 +2049,7 @@ function CityScene({
2018
2049
  centerOffset={centerOffset}
2019
2050
  opacity={1}
2020
2051
  highlightColor={districtColor}
2052
+ growProgress={growProgress}
2021
2053
  />
2022
2054
  );
2023
2055
  })}
@@ -2,7 +2,19 @@
2
2
  * FileCity3D - 3D visualization component
3
3
  */
4
4
 
5
- export { FileCity3D, resetCamera, moveCameraTo, setCameraTarget, getCameraTarget, rotateCameraTo, rotateCameraBy, tiltCameraTo, tiltCameraBy, getCameraPosition, getCameraAngle, getCameraTilt } from './FileCity3D';
5
+ export {
6
+ FileCity3D,
7
+ resetCamera,
8
+ getCameraAngle,
9
+ getCameraTarget,
10
+ getCameraTilt,
11
+ rotateCameraTo,
12
+ rotateCameraBy,
13
+ tiltCameraTo,
14
+ tiltCameraBy,
15
+ moveCameraTo,
16
+ setCameraTarget,
17
+ } from './FileCity3D';
6
18
  export type {
7
19
  FileCity3DProps,
8
20
  AnimationConfig,
@@ -13,5 +25,4 @@ export type {
13
25
  CityData,
14
26
  CityBuilding,
15
27
  CityDistrict,
16
- RotateOptions,
17
28
  } from './FileCity3D';