From c0eebacd3b7b342031a0b4fe0f272c89d97931a2 Mon Sep 17 00:00:00 2001
From: "Behrisch, M. (Michael)" <m.behrisch@uu.nl>
Date: Tue, 20 Feb 2024 13:09:22 +0000
Subject: [PATCH] fix: fixes ordering, font scaling, and disable visibility for
 too small labels

---
 .gitignore                                    |   1 -
 .../matrix/components/BitmapTextLabel.ts      |  20 ++
 .../components/ColumnGraphicsComponent.tsx    |  22 ++
 .../matrix/components/ColumnLabelTrack.tsx    |  20 ++
 .../components/ColumnSpriteComponent.tsx      |  12 +
 .../matrix/components/MatrixPixi.tsx          | 322 ++++++++++++------
 .../matrix/components/ReorderingManager.tsx   |  59 +++-
 .../matrix/components/TextLabel.ts            |  34 ++
 .../visualizations/matrix/matrix.stories.tsx  |  31 +-
 .../vis/visualizations/matrix/matrixvis.tsx   |  22 +-
 .../visualizations/nodelink/nodelinkvis.tsx   |   1 -
 libs/shared/package.json                      |   9 +-
 pnpm-lock.yaml                                |  19 +-
 13 files changed, 454 insertions(+), 118 deletions(-)
 create mode 100644 libs/shared/lib/vis/visualizations/matrix/components/BitmapTextLabel.ts
 create mode 100644 libs/shared/lib/vis/visualizations/matrix/components/ColumnLabelTrack.tsx
 create mode 100644 libs/shared/lib/vis/visualizations/matrix/components/TextLabel.ts

diff --git a/.gitignore b/.gitignore
index 7749c1bd2..6411dbf0d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -80,7 +80,6 @@ node_modules
 tsconfig.tsbuildinfo
 vite.config.ts.*
 
-
 # Generated ts definitions files for CSS modules
 *.d.ts
 *.module.scss.d.ts
diff --git a/libs/shared/lib/vis/visualizations/matrix/components/BitmapTextLabel.ts b/libs/shared/lib/vis/visualizations/matrix/components/BitmapTextLabel.ts
new file mode 100644
index 000000000..4cc2a1d44
--- /dev/null
+++ b/libs/shared/lib/vis/visualizations/matrix/components/BitmapTextLabel.ts
@@ -0,0 +1,20 @@
+import { BitmapText, Text } from 'pixi.js';
+
+export class BitmapTextLabel extends BitmapText {
+  static readonly LABEL_FONT_FAMILY = 'HelveticaRegular';
+  static readonly LABEL_FONT_SIZE = 12;
+  static readonly LABEL_COLOR = 0x333333;
+
+  constructor(label: string) {
+    super(label, {
+      fontName: BitmapTextLabel.LABEL_FONT_FAMILY,
+      fontSize: BitmapTextLabel.LABEL_FONT_SIZE,
+      align: 'right',
+      tint: BitmapTextLabel.LABEL_COLOR,
+    });
+
+    this.rotation = (Math.PI * 3) / 2;
+    this.eventMode = 'none';
+    this.name = 'Text_' + label;
+  }
+}
diff --git a/libs/shared/lib/vis/visualizations/matrix/components/ColumnGraphicsComponent.tsx b/libs/shared/lib/vis/visualizations/matrix/components/ColumnGraphicsComponent.tsx
index 7226749f9..facb7ff10 100644
--- a/libs/shared/lib/vis/visualizations/matrix/components/ColumnGraphicsComponent.tsx
+++ b/libs/shared/lib/vis/visualizations/matrix/components/ColumnGraphicsComponent.tsx
@@ -50,9 +50,14 @@ export const createColumn = (
       gfx.drawRect(0, i * cellWidth, cellWidth, cellHeight);
       gfx.endFill();
     } else {
+      // console.log('inOutEdge', inOutEdge, Math.min(inOutEdge.length, 1), currentVisMapping.colorScale(Math.min(inOutEdge.length, 1)));
+
       if (outEdges.length > 0) {
         const thisEdge = outEdges[0];
+        // console.log('inOutEdge', thisEdge);
+
         const value = byString(thisEdge, currentVisMapping.attribute);
+        // console.log('value', value);
 
         color = currentVisMapping.colorScale(value);
       }
@@ -62,8 +67,25 @@ export const createColumn = (
       gfx.drawRect(0, i * cellWidth, cellWidth, cellHeight);
       gfx.endFill();
     }
+
+    // if (inOutEdge.length > 0) {
+    //   color = fgCellColor;
+    // } else {
+    //   color = bgCellColor;
+    // }
   }
 
+  //   gfx.on('pointerdown', onButtonDown);
+  // .on('pointerup', onDragEnd).on('pointerupoutside', onDragEnd);
+
+  // for (let i = 0; i < edges.length; i++) {
+  //   const edge = edges[i];
+  //   // draw an rectangle with a fill
+  //   gfx.beginFill(0xff0000, 0.5);
+  //   gfx.drawRect(0, i * cellWidth, cellWidth, cellHeight * nodes.length);
+  //   gfx.endFill();
+  // }
+
   return gfx;
 };
 
diff --git a/libs/shared/lib/vis/visualizations/matrix/components/ColumnLabelTrack.tsx b/libs/shared/lib/vis/visualizations/matrix/components/ColumnLabelTrack.tsx
new file mode 100644
index 000000000..c0c00410d
--- /dev/null
+++ b/libs/shared/lib/vis/visualizations/matrix/components/ColumnLabelTrack.tsx
@@ -0,0 +1,20 @@
+import { useEffect } from 'react';
+
+export const ColumnLabelTrack = ({ columnLabels, config }: { columnLabels: string[]; config: any }) => {
+  //   console.log('ColumnLabelTrack', columnLabels);
+
+  return (
+    <>
+      <div className="grid grid-flow-col auto-cols-max h-80">
+        {columnLabels.map((label, index) => {
+          // console.log('columnlabeltrack', label);
+          return (
+            <div className="-rotate-90 font-mono text-sm w-4" key={index}>
+              {label}
+            </div>
+          );
+        })}
+      </div>
+    </>
+  );
+};
diff --git a/libs/shared/lib/vis/visualizations/matrix/components/ColumnSpriteComponent.tsx b/libs/shared/lib/vis/visualizations/matrix/components/ColumnSpriteComponent.tsx
index 6176f1d5b..b04470376 100644
--- a/libs/shared/lib/vis/visualizations/matrix/components/ColumnSpriteComponent.tsx
+++ b/libs/shared/lib/vis/visualizations/matrix/components/ColumnSpriteComponent.tsx
@@ -11,6 +11,7 @@ export const createColumn = (
   cellWidth: number,
   cellHeight: number
 ) => {
+  // console.log('createColumn', id, nodes.length, edges.length);
   const sprite = new Sprite(Texture.WHITE);
   sprite.name = 'col_' + id;
   sprite.eventMode = 'static';
@@ -19,6 +20,8 @@ export const createColumn = (
   const edgesForThisColumn = edges.filter((edge) => {
     return edge.from === nodesCol[id].id || edge.to === nodesCol[id].id;
   });
+  // console.log('edgesForThisColumn', nodesCol[id].id, edgesForThisColumn);
+  // const color = new Color({ r: 255 * (id / nodesCol.length), g: 255, b: 255, a: 1 });
   const bgCellColor = dataColors.neutral['5'];
   const fgCellColor = tailwindColors.entity.DEFAULT;
   let color = bgCellColor;
@@ -44,5 +47,14 @@ export const createColumn = (
     // sprite.drawRect(0, i * cellWidth, cellWidth, cellHeight);
     // sprite.endFill();
   }
+  //   sprite.on('pointerdown', onButtonDown);
+  // .on('pointerup', onDragEnd).on('pointerupoutside', onDragEnd);
+  // for (let i = 0; i < edges.length; i++) {
+  //   const edge = edges[i];
+  //   // draw an rectangle with a fill
+  //   gfx.beginFill(0xff0000, 0.5);
+  //   gfx.drawRect(0, i * cellWidth, cellWidth, cellHeight * nodes.length);
+  //   gfx.endFill();
+  // }
   return sprite;
 };
diff --git a/libs/shared/lib/vis/visualizations/matrix/components/MatrixPixi.tsx b/libs/shared/lib/vis/visualizations/matrix/components/MatrixPixi.tsx
index 550a1cef5..772898d3c 100644
--- a/libs/shared/lib/vis/visualizations/matrix/components/MatrixPixi.tsx
+++ b/libs/shared/lib/vis/visualizations/matrix/components/MatrixPixi.tsx
@@ -1,4 +1,5 @@
 import { Edge, GraphQueryResult, Node, useML, useSearchResultData } from '@graphpolaris/shared/lib/data-access';
+import { Cull } from '@pixi-essentials/cull';
 import { dataColors, tailwindColors } from 'config';
 import * as d3 from 'd3';
 import { Viewport } from 'pixi-viewport';
@@ -25,6 +26,7 @@ import Color from 'color';
 import { localConfigSchemaType } from '../../../Types';
 import { createColumn } from './ColumnGraphicsComponent';
 import { ReorderingManager } from './ReorderingManager';
+import { TextLabel } from './TextLabel';
 
 type Props = {
   // onClick: (node: NodeType, pos: IPointData) => void;
@@ -38,30 +40,41 @@ type Props = {
 };
 
 const app = new Application({ background: 0xffffff, antialias: true, autoDensity: true, eventMode: 'auto' });
-const columnsContainer = new Container();
-const columnAxisContainer = new Container();
-const rowsContainer = new Container();
-
 //////////////////
 // MAIN COMPONENT
 //////////////////
-
 export const MatrixPixi = (props: Props) => {
+  const columnLayer = new Container();
+  const columnLabelLayer = new Container();
+  const rowsLabelLayer = new Container();
+
+  let lastZoom = Infinity;
+
   let config = {
     textOffsetX: 100,
     textOffsetY: 100,
     visMapping: [] as any[], // TODO type
 
-    cellHeight: 100,
-    cellWidth: 100,
+    CELL_HEIGHT: 50,
+    CELL_WIDTH: 50,
+
+    LABEL_FONT_FAMILY: 'Roboto',
+    LABEL_FILL: 0x000000,
+    LABEL_ALIGN: 'center',
+    LABEL_FONT_SIZE: 25,
+    LABEL_MARGIN: 4,
+    LABEL_MIN_WIDTH: 6,
+
+    ANIMATION_DURATION: 0.8,
   };
 
   let columnOrder: string[] = [];
   let rowOrder: string[] = [];
+  const [columnOrderState, setColumnOrderState] = useState<string[]>([]);
+  const [rowOrderState, setRowOrderState] = useState<string[]>([]);
 
   const [quickPopup, setQuickPopup] = useState<{ node: NodeType; pos: IPointData } | undefined>();
   const [popups, setPopups] = useState<{ node: NodeType; pos: IPointData }[]>([]);
-  // const [columnOrder, setColumnOrder] = useState<string[]>([]);
 
   const nodeMap = useRef(new Map<string, Graphics>());
   const linkMap = useRef(new Map<string, Graphics>());
@@ -71,7 +84,8 @@ export const MatrixPixi = (props: Props) => {
   const ml = useML();
   const searchResults = useSearchResultData();
 
-  // const imperative = useRef<any>(null);
+  const cull = new Cull();
+  let cullDirty = useRef(true);
 
   function resize() {
     const width = ref?.current?.clientWidth || 1000;
@@ -107,8 +121,11 @@ export const MatrixPixi = (props: Props) => {
     }
   }, [ref]);
 
+  // useEffect(() => {
+  //   console.log('newColumnOrder', columnOrder);
+  // }, [columnOrder]);
+
   useEffect(() => {
-    console.log('graph change');
     // console.log('graph changed', props.graph, ref.current, ref.current.children.length > 0, imperative.current);
     if (props.graph && ref.current && ref.current.children.length > 0) {
       if (!isSetup.current) setup();
@@ -117,7 +134,6 @@ export const MatrixPixi = (props: Props) => {
   }, [props.graph]);
 
   useEffect(() => {
-    console.log('config change');
     // console.log('graph changed', props.graph, ref.current, ref.current.children.length > 0, imperative.current);
     if (props.graph && ref.current && ref.current.children.length > 0) {
       setup();
@@ -158,45 +174,45 @@ export const MatrixPixi = (props: Props) => {
       if (forceClear) {
         nodeMap.current.clear();
         linkMap.current.clear();
-        rowsContainer.removeChildren();
-        columnsContainer.removeChildren();
+        rowsLabelLayer.removeChildren();
+        columnLayer.removeChildren();
       }
     }
   };
 
   const onHoverColumn = (event: any, currentNode: Node | null) => {
-    app.renderer.plugins.interaction.cursorStyles.pointer = 'crosshair';
+    app.renderer.events.cursorStyles.pointer = 'crosshair';
     if (!currentNode) {
-      rowsContainer.children.forEach((row) => {
+      rowsLabelLayer.children.forEach((row) => {
         row.alpha = 1;
       });
-      columnsContainer.children.forEach((col) => {
+      columnLayer.children.forEach((col) => {
         col.alpha = 1;
       });
-      columnAxisContainer.children.forEach((colText) => {
+      columnLabelLayer.children.forEach((colText) => {
         colText.alpha = 1;
       });
 
       return;
     }
 
-    columnsContainer.children.forEach((col) => {
+    columnLayer.children.forEach((col) => {
       col.alpha = 0.25;
     });
     event.currentTarget.alpha = 1;
 
-    columnAxisContainer.children.forEach((colText) => {
+    columnLabelLayer.children.forEach((colText) => {
       colText.alpha = 0.25;
       if (colText.name?.endsWith(currentNode.id)) colText.alpha = 1;
     });
 
     if (!props.graph) return;
-    rowsContainer.children.forEach((col) => {
+    rowsLabelLayer.children.forEach((col) => {
       col.alpha = 0.25;
     });
 
     if (!props.graph) return;
-    rowsContainer.children.forEach((col) => {
+    rowsLabelLayer.children.forEach((col) => {
       col.alpha = 0.25;
     });
 
@@ -206,17 +222,17 @@ export const MatrixPixi = (props: Props) => {
     });
 
     edgesForThisColumn.forEach((edge) => {
-      let row = rowsContainer.getChildByName(edge.to);
+      let row = rowsLabelLayer.getChildByName(edge.to);
       if (row) row.alpha = 1;
 
-      row = rowsContainer.getChildByName(edge.from);
+      row = rowsLabelLayer.getChildByName(edge.from);
       if (row) row.alpha = 1;
     });
   };
 
   const reorderColumns = (columnOrder: string[]) => {
-    const columns = columnsContainer.children;
-    const columnsText = columnAxisContainer.children;
+    const columns = columnLayer.children;
+    const columnLabels = columnLabelLayer.children;
     let columnPositions: Point[] = [];
     for (let i = 0; i < columns.length; i++) {
       const col = columns[i];
@@ -224,8 +240,8 @@ export const MatrixPixi = (props: Props) => {
     }
 
     let columnTextPositions: Point[] = [];
-    for (let i = 0; i < columnsText.length; i++) {
-      const col = columnsText[i];
+    for (let i = 0; i < columnLabels.length; i++) {
+      const col = columnLabels[i];
       columnTextPositions.push(new Point(col.position.x, col.position.y));
     }
 
@@ -246,7 +262,7 @@ export const MatrixPixi = (props: Props) => {
 
       const newPositionText = columnTextPositions[index];
       // move column to new position
-      Actions.moveTo(columnsText[i], newPositionText.x, newPositionText.y, 1, Interpolations.pow2out).play();
+      Actions.moveTo(columnLabels[i], newPositionText.x, newPositionText.y, 1, Interpolations.pow2out).play();
     }
   };
 
@@ -259,7 +275,7 @@ export const MatrixPixi = (props: Props) => {
     cellWidth: number,
     cellHeight: number
   ) => {
-    const rows = rowsContainer.children;
+    const rows = rowsLabelLayer.children;
     let rowPositions: Point[] = [];
     for (let i = 0; i < rows.length; i++) {
       const row = rows[i];
@@ -277,34 +293,35 @@ export const MatrixPixi = (props: Props) => {
       Actions.moveTo(row, newPosition.x, newPosition.y, 1, Interpolations.pow2out).play();
     }
 
-    const colOrder = columnsContainer.children.map((col) => col.name) as string[];
+    const colOrder = columnLayer.children.map((col) => col.name) as string[];
     console.log('colOrder', colOrder);
     if (!colOrder) throw new Error('colOrder is undefined');
-    columnsContainer.removeChildren();
+    columnLayer.removeChildren();
     setupColumns(edges, colOrder, rowOrder);
   };
 
   const setup = () => {
     if (!props.graph) throw Error('Graph is undefined; setup not possible');
-    columnsContainer.removeChildren();
-    rowsContainer.removeChildren();
-    columnAxisContainer.removeChildren();
+    console.log('setup matrixvis with graph:', props.graph);
+
+    columnLayer.removeChildren();
+    rowsLabelLayer.removeChildren();
+    columnLabelLayer.removeChildren();
+    viewport.current?.removeAllListeners();
+    viewport.current?.removeChildren();
     app.stage.removeChildren();
 
     const size = ref.current?.getBoundingClientRect();
     viewport.current = new Viewport({
       screenWidth: size?.width || 1000,
       screenHeight: size?.height || 1000,
-      worldWidth: size?.width || 1000,
-      worldHeight: size?.height || 1000,
       stopPropagation: true,
       events: app.renderer.events, // the interaction module is important for wheel to work properly when renderer.view is placed or scaled
     });
 
-    app.stage.addChild(viewport.current);
+    // setupZoomLogic();
 
-    viewport.current.addChild(columnsContainer);
-    viewport.current.addChild(rowsContainer);
+    viewport.current.addChild(columnLayer);
 
     const groupByType = props.graph.nodes.reduce((group: any, node: Node) => {
       if (!group[node.label]) group[node.label] = [];
@@ -345,30 +362,126 @@ export const MatrixPixi = (props: Props) => {
     columnOrder = newOrdering.columnOrder;
     rowOrder = newOrdering.rowOrder;
 
-    config.cellWidth = Math.max((size?.width || 1000) / props.graph.nodes.length, (size?.height || 1000) / props.graph.nodes.length);
-    config.cellHeight = config.cellWidth;
-
-    // console.log('currentColumnOrder', columnOrder);
-
     setupVisualizationEncodingMapping(props.localConfig);
 
     setupColumns(props.graph.edges, columnOrder, rowOrder);
-    setupColumnLegend(columnOrder);
+    setupColumnLabels(columnOrder);
     setupColumnInteractivity(cols);
 
-    setupRowLegend(rows, rowOrder);
+    setupRowLabels(rows, rowOrder);
     setupRowInteractivity(cols, rows, rowOrder, d3.scaleOrdinal(d3.schemeCategory10));
 
-    console.log('setup matrixvis with graph:', props.graph);
-
     // activate plugins
     viewport.current.drag().pinch().wheel().animate({}).decelerate({ friction: 0.75 });
+    lastZoom = viewport.current.scale.x;
 
+    app.stage.addChild(viewport.current);
     app.ticker.add(tick);
+
+    // requestRender();
     update();
     isSetup.current = true;
+
+    cull.clear();
+    cull.addAll(viewport.current.children);
+    cull.addAll(rowsLabelLayer.children);
+    cull.addAll(columnLabelLayer.children);
+    cull.addAll(columnLayer.children);
+    cullDirty.current = true;
+
+    setColumnOrderState([...columnOrder]);
+    setRowOrderState([...rowOrder]);
+
+    resetViewport();
   };
 
+  // let renderRequestId: number | undefined = undefined;
+  // const requestRender = () => {
+  //   if (renderRequestId) {
+  //     return;
+  //   }
+  //   renderRequestId = window.requestAnimationFrame(() => {
+  //     app.render();
+  //     renderRequestId = undefined;
+  //   });
+  // };
+
+  const updateVisibility = () => {
+    if (!viewport.current) return;
+
+    // culling
+    if (viewport.current.dirty || cullDirty.current) {
+      cull.cull(app.renderer.screen);
+      // console.log(
+      //   'culling',
+      //   [...viewport.current.children].filter((x) => x.visible === true).length,
+      //   [...viewport.current.children].filter((x) => x.visible === false).length,
+      //   [...rowsLabelLayer.children].filter((x) => x.visible === true).length,
+      //   [...rowsLabelLayer.children].filter((x) => x.visible === false).length,
+      //   [...columnLabelLayer.children].filter((x) => x.visible === true).length,
+      //   [...columnLabelLayer.children].filter((x) => x.visible === false).length,
+      //   [...columnLayer.children].filter((x) => x.visible === true).length,
+      //   [...columnLayer.children].filter((x) => x.visible === false).length
+      // );
+
+      viewport.current.dirty = false;
+      cullDirty.current = false;
+    }
+
+    // levels of detail
+    // if (viewport.current?.scale.x !== lastZoom) {
+    const zoom = viewport.current?.scale.x || 0.0;
+
+    const oneColumn = columnLayer.children[0];
+    if (!oneColumn) return;
+
+    const targetLabelWidth = oneColumn.getBounds().width;
+    const targetLabelHeight = targetLabelWidth; //cells have same width and height
+
+    [...columnLabelLayer.children]
+      .filter((x) => x.visible === true)
+      .forEach((columnItem) => {
+        if (targetLabelWidth < config.LABEL_MIN_WIDTH) {
+          columnItem.visible = false;
+        } else {
+          const textLabel = columnItem as TextLabel;
+          textLabel.visible = true;
+        }
+      });
+
+    [...rowsLabelLayer.children]
+      .filter((x) => x.visible === true)
+      .forEach((rowItem) => {
+        if (targetLabelWidth < config.LABEL_MIN_WIDTH) {
+          rowItem.visible = false;
+        } else {
+          rowItem.visible = true;
+        }
+      });
+
+    lastZoom = zoom;
+    // }
+  };
+
+  // TODO
+  // const setupZoomLogic = () => {
+  //   const zoomIn = () => {
+  //     if (!viewport.current) return
+  //     viewport.current.zoom(-WORLD_WIDTH / 10, true);
+  //   };
+  //   const zoomOut = () => {
+  //     if (!viewport.current) return;
+  //     viewport.current.zoom(WORLD_WIDTH / 10, true);
+  //   };
+  const resetViewport = () => {
+    if (!viewport.current) return;
+    viewport.current.center = new Point(viewport.current.worldWidth / 2, viewport.current.worldHeight / 2);
+
+    // console.log('resetViewPort', viewport.current.center);
+    viewport.current.fitWorld(true);
+  };
+  // }
+
   const setupVisualizationEncodingMapping = (localConfig: localConfigSchemaType) => {
     if (!props.graph) throw new Error('Graph is undefined; cannot setup matrix');
     const visMapping = []; // TODO type
@@ -391,10 +504,10 @@ export const MatrixPixi = (props: Props) => {
 
         gfxContext.lineStyle(2, 0xffffff);
         if (this.encoding === 'rect') {
-          gfxContext.drawRect(0, i * config.cellHeight, config.cellWidth, config.cellHeight);
+          gfxContext.drawRect(0, i * config.CELL_HEIGHT, config.CELL_WIDTH, config.CELL_HEIGHT);
         }
         if (this.encoding === 'circle') {
-          gfxContext.drawCircle(config.cellWidth / 2, i * config.cellHeight + config.cellHeight / 2, config.cellWidth / 2);
+          gfxContext.drawCircle(config.CELL_WIDTH / 2, i * config.CELL_HEIGHT + config.CELL_HEIGHT / 2, config.CELL_WIDTH / 2);
         }
         gfxContext.endFill();
 
@@ -442,20 +555,28 @@ export const MatrixPixi = (props: Props) => {
       });
       // console.log('edgesForThisColumn', oneColumn.name, edgesForThisColumn);
 
-      const col = createColumn(rowOrder, edgesForThisColumn, config.visMapping, config.cellWidth, config.cellHeight);
+      const col = createColumn(rowOrder, edgesForThisColumn, config.visMapping, config.CELL_WIDTH, config.CELL_HEIGHT);
       oneColumn.addChild(col);
-      oneColumn.position.set(j * config.cellWidth + config.textOffsetX, config.textOffsetY);
-
-      columnsContainer.addChild(oneColumn);
-      oneColumn.alpha = 0;
-      Actions.sequence(Actions.delay(j * 0.005 * Math.random()), Actions.fadeIn(oneColumn, 0.8, Interpolations.pow2out)).play();
+      oneColumn.position.set(j * config.CELL_WIDTH + config.textOffsetX, config.textOffsetY);
+
+      columnLayer.addChild(oneColumn);
+
+      if (columnOrder.length < 100) {
+        oneColumn.alpha = 0;
+        Actions.sequence(
+          Actions.delay(j * 0.005 * Math.random()),
+          Actions.fadeIn(oneColumn, config.ANIMATION_DURATION, Interpolations.pow2out)
+        ).play();
+      } else {
+        oneColumn.alpha = 1;
+      }
     }
   }
 
   const setupColumnInteractivity = (cols: Node[]) => {
-    for (let j = 0; j < columnsContainer.children.length; j++) {
-      const oneColumn = columnsContainer.children[j];
-      oneColumn.interactive = true;
+    for (let j = 0; j < columnLayer.children.length; j++) {
+      const oneColumn = columnLayer.children[j];
+      oneColumn.eventMode = 'dynamic';
       oneColumn.on('pointerdown', onButtonDown);
       oneColumn.on('pointerover', (event) => {
         const col = cols.find((col) => col.id === oneColumn.name);
@@ -467,34 +588,28 @@ export const MatrixPixi = (props: Props) => {
     }
   };
 
-  const setupColumnLegend = (columnOrder: string[]) => {
-    // console.log('setupColumnLegend');
-    // columnAxisContainer.removeChildren();
-    columnAxisContainer.position.set(config.textOffsetX, 0);
+  const setupColumnLabels = (columnOrder: string[]) => {
+    columnLabelLayer.removeChildren();
+
+    columnLabelLayer.position.set(config.textOffsetX, 0);
     for (let j = 0; j < columnOrder.length; j++) {
-      // from the PixiJS documention: Setting a text object's scale to > 1.0 will result in blurry/pixely display,
-      // because the text is not re-rendered at the higher resolution needed to look sharp -
-      // it's still the same resolution it was when generated. To deal with this, you can render at a higher
-      // initial size and down-scale, instead.
-      const finalTextSize = 10;
-      const bigRandomScaleFactor = 10;
-      const basicText = new Text(columnOrder[j], { fontSize: finalTextSize * bigRandomScaleFactor, fill: 0x000000, align: 'center' });
-      basicText.position.set(j * config.cellWidth + config.cellWidth / 4, config.textOffsetY - 5);
-      basicText.scale.set(finalTextSize / (bigRandomScaleFactor * bigRandomScaleFactor));
-      basicText.rotation = (Math.PI * 3) / 2;
-      basicText.eventMode = 'none';
-      basicText.name = 'Text_' + columnOrder[j];
-      columnAxisContainer.addChild(basicText);
+      const textLabel = new TextLabel(columnOrder[j], config);
+      // const textLabel = new BitmapTextLabel(columnOrder[j]);
+
+      // console.log('font resolved', columnOrder[j]);
+      textLabel.position.set(j * config.CELL_WIDTH + config.CELL_WIDTH / 4, config.textOffsetY - 5);
+      columnLabelLayer.addChild(textLabel);
     }
-    viewport.current?.addChild(columnAxisContainer);
+    viewport.current?.addChild(columnLabelLayer);
 
     const columnAxis = new Sprite(Texture.WHITE);
-    columnAxis.width = columnOrder.length * config.cellWidth;
+    columnAxis.width = columnOrder.length * config.CELL_WIDTH;
     columnAxis.height = config.textOffsetY;
     columnAxis.tint = 0xaaaaaa;
     columnAxis.position.set(config.textOffsetX, 0);
     columnAxis.alpha = 0.0;
-    columnAxis.interactive = true;
+    // columnAxis.interactive = true;
+    columnAxis.eventMode = 'dynamic';
     columnAxis.on('pointerdown', (event) => {
       // const reordering = new ReorderColumnsAction(columnOrder);
 
@@ -508,10 +623,10 @@ export const MatrixPixi = (props: Props) => {
     });
     // columnAxis.on('pointerdown', reorderColumns);
     columnAxis.on('pointerover', (event) => {
-      Actions.fadeTo(columnAxis, 0.5, 0.5, Interpolations.pow2out).play();
+      Actions.fadeTo(columnAxis, 0.5, config.ANIMATION_DURATION, Interpolations.pow2out).play();
     });
     columnAxis.on('pointerout', (event) => {
-      Actions.fadeTo(columnAxis, 0.0, 0.5, Interpolations.pow2out).play();
+      Actions.fadeTo(columnAxis, 0.0, config.ANIMATION_DURATION, Interpolations.pow2out).play();
     });
     viewport.current?.addChild(columnAxis);
   };
@@ -535,35 +650,46 @@ export const MatrixPixi = (props: Props) => {
     return array;
   }
 
-  function setupRowLegend(rows: Node[], rowOrder: string[]) {
+  function setupRowLabels(rows: Node[], rowOrder: string[]) {
+    rowsLabelLayer.removeChildren();
+
+    // columnLabelLayer.position.set(config.textOffsetX, 0);
     for (let i = 0; i < rowOrder.length; i++) {
       const rowID = rowOrder[i];
-      const finalTextSize = 10;
-      const bigRandomScaleFactor = 10;
-      const basicText = new Text(rowID, { fontSize: finalTextSize * bigRandomScaleFactor, fill: 0x000000, align: 'right' });
-      basicText.anchor.x = 1;
-      basicText.anchor.y = 0;
-      basicText.scale.set(finalTextSize / (bigRandomScaleFactor * bigRandomScaleFactor));
-      basicText.position.set(config.textOffsetX - 5, i * config.cellHeight + config.textOffsetY + config.cellHeight / 4);
-      basicText.name = rowID;
-      rowsContainer.addChild(basicText);
-
-      Actions.sequence(Actions.delay(i * 0.005 * Math.random()), Actions.fadeIn(basicText, 0.5, Interpolations.pow2out)).play();
+      const textLabel = new TextLabel(rowID, config);
+      textLabel.anchor.x = 1;
+      textLabel.anchor.y = 0;
+      textLabel.rotation = 0;
+      textLabel.name = rowID;
+      textLabel.position.set(config.textOffsetX - 5, i * config.CELL_HEIGHT + config.textOffsetY + config.CELL_HEIGHT / 4);
+      rowsLabelLayer.addChild(textLabel);
+
+      if (rowOrder.length < 100) {
+        textLabel.alpha = 0;
+        Actions.sequence(
+          Actions.delay(i * 0.005 * Math.random()),
+          Actions.fadeIn(textLabel, config.ANIMATION_DURATION, Interpolations.pow2out)
+        ).play();
+      } else {
+        textLabel.alpha = 1;
+      }
     }
+
+    viewport.current?.addChild(rowsLabelLayer);
   }
 
   const setupRowInteractivity = (cols: Node[], rows: Node[], rowOrder: string[], colorScale: any) => {
     const rowAxis = new Sprite(Texture.WHITE);
     rowAxis.width = config.textOffsetX;
-    rowAxis.height = rows.length * config.cellHeight;
+    rowAxis.height = rows.length * config.CELL_HEIGHT;
     rowAxis.tint = 0xaaaaaa;
     rowAxis.position.set(0, config.textOffsetY);
     rowAxis.alpha = 0.0;
-    rowAxis.interactive = true;
+    rowAxis.eventMode = 'dynamic';
     rowAxis.on('pointerdown', (event) => {
       if (props.graph) {
         rowOrder = shuffle(rowOrder);
-        reorderRows(cols, rows, props?.graph.edges, rowOrder, colorScale, config.cellWidth, config.cellHeight);
+        reorderRows(cols, rows, props?.graph.edges, rowOrder, colorScale, config.CELL_WIDTH, config.CELL_HEIGHT);
       }
     });
     rowAxis.on('pointerover', (event) => {
@@ -578,6 +704,8 @@ export const MatrixPixi = (props: Props) => {
   const tick = (delta: number) => {
     if (props.graph) {
       Actions.tick(delta / 60);
+
+      updateVisibility();
     }
   };
 
@@ -587,6 +715,8 @@ export const MatrixPixi = (props: Props) => {
         <NLPopup onClose={() => {}} data={popup} key={popup.node.id} />
       ))}
       {quickPopup && <NLPopup onClose={() => {}} data={quickPopup} />}
+
+      {/* {columnOrderState.length > 0 && <ColumnLabelTrack columnLabels={columnOrderState} config={config} />} */}
       <div className="h-full w-full overflow-hidden" ref={ref}></div>
     </>
   );
diff --git a/libs/shared/lib/vis/visualizations/matrix/components/ReorderingManager.tsx b/libs/shared/lib/vis/visualizations/matrix/components/ReorderingManager.tsx
index ae69d44e2..a843663d3 100644
--- a/libs/shared/lib/vis/visualizations/matrix/components/ReorderingManager.tsx
+++ b/libs/shared/lib/vis/visualizations/matrix/components/ReorderingManager.tsx
@@ -10,6 +10,27 @@ export class ReorderingManager {
     this.graph = graph;
   }
 
+  //   // Precompute the orders.
+  //   orders = {
+  //     //
+  //     //   name: d3.range(n).sort(function (a, b) {
+  //     //     return d3.ascending(nodes[a].name, nodes[b].name);
+  //     //   }),
+  //     //   count: d3.range(n).sort(function (a, b) {
+  //     //     return nodes[b].count - nodes[a].count;
+  //     //   }),
+  //     //   group: d3.range(n).sort(function (a, b) {
+  //     //     var x = nodes[b].group - nodes[a].group;
+  //     //     return x != 0 ? x : d3.ascending(nodes[a].name, nodes[b].name);
+  //     //   }),
+  //     leafOrder: computeLeaforder,
+  //     //   leafOrderDist: computeLeaforderDist,
+  //     //   barycenter: computeBarycenter,
+  //     //   rcm: computeRCM,
+  //     //   spectral: computeSpectral,
+  //     //   nn2opt: computeNN2OPT,
+  //   };
+
   private computeNameOrder = (columnOrder: string[], rowOrder: string[]) => {
     const columnOrderSorted = columnOrder.sort((a, b) => a.localeCompare(b));
     const rowOrderSorted = rowOrder.sort((a, b) => a.localeCompare(b));
@@ -80,6 +101,8 @@ export class ReorderingManager {
       adjacency.push(rowOrderIDs);
     }
 
+    // console.log('adjacency', adjacency);
+
     return adjacency;
   }
 
@@ -114,6 +137,9 @@ export class ReorderingManager {
     );
 
     const nodes = columnOrder.map((id) => nodesTemp.find((node) => node.id === id));
+    const nodesWithRows = nodes.push(...rowOrder.map((id) => nodesTemp.find((node) => node.id === id)));
+    console.log('nodesTemp', nodes);
+
     const graphReorderJs = reorderAny.graph().nodes(nodes);
 
     const edges = graph.edges.map((edge) => {
@@ -130,6 +156,7 @@ export class ReorderingManager {
       } as any;
     });
 
+    // const edges = rowOrder.map((id) => edgesTemp.find((edge) => edge.id === id));
     graphReorderJs.links(edges);
     graphReorderJs.init();
 
@@ -154,6 +181,14 @@ export class ReorderingManager {
     const reorderGraph = this.getReorderJSGraph(this.graph, columnOrder, rowOrder);
 
     var order = reorderAny.spectral_order(reorderGraph);
+    // rcm.forEach(function (lo, i) {
+    //   nodes[i].rcm = lo;
+    // });
+
+    // return nodes.map(function (n) {
+    //   return n.rcm;
+    // });
+
     const columnOrderSorted = order.map((i: number) => columnOrder[i]).filter((a: string) => columnOrder.includes(a));
     const rowOrderSorted = order.map((i: number) => rowOrder[i]).filter((a: string) => rowOrder.includes(a));
 
@@ -167,6 +202,13 @@ export class ReorderingManager {
     const reorderGraph = this.getReorderJSGraph(this.graph, columnOrder, rowOrder);
 
     var order = reorderAny.bfs_order(reorderGraph);
+    // rcm.forEach(function (lo, i) {
+    //   nodes[i].rcm = lo;
+    // });
+
+    // return nodes.map(function (n) {
+    //   return n.rcm;
+    // });
 
     const columnOrderSorted = order.map((i: number) => columnOrder[i]).filter((a: string) => columnOrder.includes(a));
     const rowOrderSorted = order.map((i: number) => rowOrder[i]).filter((a: string) => rowOrder.includes(a));
@@ -183,6 +225,7 @@ export class ReorderingManager {
 
     const order = reorderAny.pca_order(columnOrderUnSorted);
     const columnOrderSorted = order.map((i: number) => columnOrder[i]);
+    // const rowOrderSorted = order.map((i: number) => rowOrder[i]).filter((a: string) => rowOrder.includes(a));
 
     console.debug('improved pca', order, columnOrderSorted, rowOrder);
 
@@ -193,22 +236,22 @@ export class ReorderingManager {
     console.log('reorderMatrix', orderingname);
     switch (orderingname.toLowerCase()) {
       case 'leafordering': {
-        return this.computeLeaforder(columnOrder, rowOrder);
+        return this.computeLeaforder(columnOrder, rowOrder) as { columnOrder: string[]; rowOrder: string[] };
       }
       case 'name': {
-        return this.computeNameOrder(columnOrder, rowOrder);
+        return this.computeNameOrder(columnOrder, rowOrder) as { columnOrder: string[]; rowOrder: string[] };
       }
       case 'count': {
-        return this.computeCountOrder(columnOrder, rowOrder);
+        return this.computeCountOrder(columnOrder, rowOrder) as { columnOrder: string[]; rowOrder: string[] };
       }
       case 'barycenter': {
-        return this.computeBarycenter(columnOrder, rowOrder);
+        return this.computeBarycenter(columnOrder, rowOrder) as { columnOrder: string[]; rowOrder: string[] };
       }
       case 'rcm': {
-        return this.computeRCM(columnOrder, rowOrder);
+        return this.computeRCM(columnOrder, rowOrder) as { columnOrder: string[]; rowOrder: string[] };
       }
       case 'spectral': {
-        return this.computeSpectal(columnOrder, rowOrder);
+        return this.computeSpectal(columnOrder, rowOrder) as { columnOrder: string[]; rowOrder: string[] };
       }
       // case 'pca': {
       //   return this.computePCA(columnOrder, rowOrder);
@@ -217,10 +260,10 @@ export class ReorderingManager {
       //   return this.computeBFS(columnOrder, rowOrder);
       // }
       case 'none' || 'identity': {
-        return { columnOrder, rowOrder };
+        return { columnOrder, rowOrder } as { columnOrder: string[]; rowOrder: string[] };
       }
       default: {
-        return this.computeLeaforder(columnOrder, rowOrder);
+        return this.computeLeaforder(columnOrder, rowOrder) as { columnOrder: string[]; rowOrder: string[] };
       }
     }
   };
diff --git a/libs/shared/lib/vis/visualizations/matrix/components/TextLabel.ts b/libs/shared/lib/vis/visualizations/matrix/components/TextLabel.ts
new file mode 100644
index 000000000..7e6e88d38
--- /dev/null
+++ b/libs/shared/lib/vis/visualizations/matrix/components/TextLabel.ts
@@ -0,0 +1,34 @@
+import { Text } from 'pixi.js';
+
+export class TextLabel extends Text {
+  static readonly RANDOM_SCALE_FACTOR = 10.0;
+
+  constructor(label: string, config: any) {
+    super(label);
+
+    // this.style = { fontSize: this.finalTextSize * this.bigRandomScaleFactor, fill: 0x000000, align: 'center' };
+    this.style = {
+      fontSize: config.LABEL_FONT_SIZE * TextLabel.RANDOM_SCALE_FACTOR,
+      fontFamily: config.LABEL_FONT_FAMILY,
+      fill: config.LABEL_FILL,
+      align: config.LABEL_ALIGN,
+    };
+    this.scale.x = 1 / TextLabel.RANDOM_SCALE_FACTOR;
+    this.scale.y = 1 / TextLabel.RANDOM_SCALE_FACTOR;
+    this.rotation = (Math.PI * 3) / 2;
+    this.eventMode = 'none';
+    this.name = 'Text_' + label;
+    this.cacheAsBitmap = true;
+
+    //   // from the PixiJS documention: Setting a text object's scale to > 1.0 will result in blurry/pixely display,
+    //   // because the text is not re-rendered at the higher resolution needed to look sharp -
+    //   // it's still the same resolution it was when generated. To deal with this, you can render at a higher
+    //   // initial size and down-scale, instead.
+    //   const basicText = new Text(columnOrder[j], { fontSize: finalTextSize * bigRandomScaleFactor, fill: 0x000000, align: 'center' });
+    //   basicText.position.set(j * config.cellWidth + config.cellWidth / 4, config.textOffsetY - 5);
+    //   basicText.scale.set(finalTextSize / (bigRandomScaleFactor * bigRandomScaleFactor));
+    //   basicText.rotation = (Math.PI * 3) / 2;
+    //   basicText.eventMode = 'none';
+    //   basicText.name = 'Text_' + columnOrder[j];
+  }
+}
diff --git a/libs/shared/lib/vis/visualizations/matrix/matrix.stories.tsx b/libs/shared/lib/vis/visualizations/matrix/matrix.stories.tsx
index ea5977146..766845b3c 100644
--- a/libs/shared/lib/vis/visualizations/matrix/matrix.stories.tsx
+++ b/libs/shared/lib/vis/visualizations/matrix/matrix.stories.tsx
@@ -8,8 +8,19 @@ import {
   big2ndChamberSchemaRaw,
   smallFlightsQueryResults,
   mockLargeQueryResults,
+  recommendationPersonActedInMovieQueryResult,
+  recommendationPersonActedInMovieQueryResultPayload,
+  slackReactionToThreadedMessageQueryResultPayload,
 } from '../../../mock-data';
 
+// export * from './mockLargeQueryResults';
+// export * from './big2ndChamberQueryResult';
+// export * from './bigMockQueryResults';
+// export * from './mockQueryResults';
+// export * from './smallFlightsQueryResults';
+// export * from './mockMobilityQueryResult';
+// export * from './typesMockQueryResults';
+
 import { VisualizationPanel } from '../../panel/visualization';
 import {
   assignNewGraphQueryResult,
@@ -43,7 +54,7 @@ const Component: Meta<typeof VisualizationPanel> = {
   ],
 };
 
-const Mockstore: any = configureStore({
+const Mockstore = configureStore({
   reducer: {
     schema: schemaSlice.reducer,
     graphQueryResult: graphQueryResultSlice.reducer,
@@ -127,4 +138,22 @@ export const TestWithLargeQueryResult = {
   },
 };
 
+export const TestWithRecommendationPersonActedInMovieQueryResult = {
+  args: { loading: false },
+  play: async () => {
+    const dispatch = Mockstore.dispatch;
+    dispatch(assignNewGraphQueryResult(recommendationPersonActedInMovieQueryResultPayload));
+    dispatch(setActiveVisualization(Visualizations.Matrix));
+  },
+};
+
+export const TestWithSlackReactionToThreadedMessageQueryResult = {
+  args: { loading: false },
+  play: async () => {
+    const dispatch = Mockstore.dispatch;
+    dispatch(assignNewGraphQueryResult(slackReactionToThreadedMessageQueryResultPayload));
+    dispatch(setActiveVisualization(Visualizations.Matrix));
+  },
+};
+
 export default Component;
diff --git a/libs/shared/lib/vis/visualizations/matrix/matrixvis.tsx b/libs/shared/lib/vis/visualizations/matrix/matrixvis.tsx
index 689a996ff..8f1e9032b 100644
--- a/libs/shared/lib/vis/visualizations/matrix/matrixvis.tsx
+++ b/libs/shared/lib/vis/visualizations/matrix/matrixvis.tsx
@@ -21,15 +21,29 @@ export const MatrixVis = React.memo(({ data, ml, dispatch, localConfig }: Visual
 
   useEffect(() => {
     if (data) {
-      setGraph(data);
+      setGraph(
+        data
+        // parseQueryResult(graphQueryResult, ml, {
+        //   defaultX: (ref.current?.clientWidth || 1000) / 2,
+        //   defaultY: (ref.current?.clientHeight || 1000) / 2,
+        // })
+      );
     }
   }, [data, ml]);
 
   return (
     <>
-      <div className="h-full w-full overflow-hidden" ref={ref}>
-        <MatrixPixi graph={graph} highlightNodes={highlightNodes} highlightedLinks={highlightedLinks} localConfig={localConfig} />
-      </div>
+      <MatrixPixi graph={graph} highlightNodes={highlightNodes} highlightedLinks={highlightedLinks} localConfig={localConfig} />
+
+      {/* <VisConfigPanelComponent> */}
+      {/* <NodeLinkConfigPanelComponent
+               graph={this.state.graph}
+               nlViewModel={this.nodeLinkViewModel}
+            /> */}
+      {/*</VisConfigPanelComponent>*/}
+      {/*<VisConfigPanelComponent isLeft>*/}
+      {/*  <AttributesConfigPanel nodeLinkViewModel={this.nodeLinkViewModel} />*/}
+      {/* </VisConfigPanelComponent> */}
     </>
   );
 });
diff --git a/libs/shared/lib/vis/visualizations/nodelink/nodelinkvis.tsx b/libs/shared/lib/vis/visualizations/nodelink/nodelinkvis.tsx
index 67afb9d1f..827c543fd 100644
--- a/libs/shared/lib/vis/visualizations/nodelink/nodelinkvis.tsx
+++ b/libs/shared/lib/vis/visualizations/nodelink/nodelinkvis.tsx
@@ -97,7 +97,6 @@ export const NodeLinkVis = React.memo(({ data, ml, dispatch }: VisualizationProp
             onClickedNode(node, ml);
           }}
         />
-
         {/* <VisConfigPanelComponent> */}
         {/* <NodeLinkConfigPanelComponent
                graph={this.state.graph}
diff --git a/libs/shared/package.json b/libs/shared/package.json
index 13eebf5a6..8eccfd0fd 100644
--- a/libs/shared/package.json
+++ b/libs/shared/package.json
@@ -24,6 +24,7 @@
     "@emotion/styled": "^11.10.6",
     "@mui/icons-material": "^5.11.11",
     "@nebula.gl/layers": "^1.0.4",
+    "@pixi-essentials/cull": "^2.0.0",
     "@reactflow/node-resizer": "^2.0.1",
     "@reduxjs/toolkit": "^1.9.2",
     "@tisoap/react-flow-smart-edge": "^3.0.0",
@@ -33,6 +34,7 @@
     "@types/supercluster": "^7.1.0",
     "classnames": "^2.3.2",
     "color": "^4.2.3",
+    "color-string": "^1.9.1",
     "config": "workspace:*",
     "cytoscape": "^3.23.0",
     "d3": "^6.6",
@@ -50,8 +52,8 @@
     "kepler.gl": "^2.5.5",
     "keycloak-js": "^21.1.1",
     "lodash-es": "^4.17.21",
-    "pixi-viewport": "^5.0.2",
     "pixi-actions": "^1.1.10",
+    "pixi-viewport": "^5.0.2",
     "pixi.js": "^7.1.4",
     "react-color": "^2.19.3",
     "react-cookie": "^4.1.1",
@@ -63,6 +65,7 @@
     "react-window": "^1.8.9",
     "reactflow": "^11.7.0",
     "regenerator-runtime": "0.13.11",
+    "reorder.js": "^2.2.6",
     "sass": "^1.59.3",
     "scss": "^0.2.4",
     "styled-components": "^5.3.6",
@@ -70,9 +73,7 @@
     "tslib": "^2.5.0",
     "typed": "link:@deck.gl/core/typed",
     "use-immer": "^0.9.0",
-    "web-worker": "^1.2.0",
-    "reorder.js": "^2.2.6",
-    "color-string": "^1.9.1"
+    "web-worker": "^1.2.0"
   },
   "devDependencies": {
     "@iconify/json": "^2.2.95",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b5d231354..a73806f11 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -232,6 +232,9 @@ importers:
       '@nebula.gl/layers':
         specifier: ^1.0.4
         version: 1.0.4(@deck.gl/core@8.9.19)(@deck.gl/extensions@8.9.19)(@deck.gl/geo-layers@8.9.19)(@deck.gl/layers@8.9.19)(@deck.gl/mesh-layers@8.9.19)(@luma.gl/constants@8.5.20)(@luma.gl/core@8.5.20)
+      '@pixi-essentials/cull':
+        specifier: ^2.0.0
+        version: 2.0.0(@pixi/display@7.2.1)(@pixi/math@7.2.1)
       '@reactflow/node-resizer':
         specifier: ^2.0.1
         version: 2.1.0(immer@10.0.2)(react-dom@18.2.0)(react@18.2.0)
@@ -4833,6 +4836,16 @@ packages:
       '@nodelib/fs.scandir': 2.1.5
       fastq: 1.15.0
 
+  /@pixi-essentials/cull@2.0.0(@pixi/display@7.2.1)(@pixi/math@7.2.1):
+    resolution: {integrity: sha512-6hm1wfCmGItOnyKvCxrmZmOLQVIaN0MqseBweH+tLZH8ecGTIF3qb1cGQDNf9jaK6HH7s/+7m9xXvvk9e92ESw==}
+    peerDependencies:
+      '@pixi/display': ^7.0.0
+      '@pixi/math': ^7.0.0
+    dependencies:
+      '@pixi/display': 7.2.1(@pixi/core@7.2.1)
+      '@pixi/math': 7.2.1
+    dev: false
+
   /@pixi/accessibility@7.2.1(@pixi/core@7.2.1)(@pixi/display@7.2.1)(@pixi/events@7.2.1):
     resolution: {integrity: sha512-4kwcmY9CRb07grMd/3FTTpzzpsPlvutnP/xnlkxF8Bz5p2Hrg1nYYxwHzn3hZI0bMIR6oQbScxlx0ijIhVjXrA==}
     peerDependencies:
@@ -16358,7 +16371,7 @@ packages:
     dependencies:
       lilconfig: 2.1.0
       postcss: 8.4.21
-      ts-node: 10.9.1(@types/node@17.0.12)(typescript@4.9.5)
+      ts-node: 10.9.1(@types/node@18.13.0)(typescript@4.9.5)
       yaml: 1.10.2
     dev: true
 
@@ -20537,8 +20550,8 @@ packages:
       tinybench: 2.4.0
       tinypool: 0.4.0
       tinyspy: 1.1.1
-      vite: 4.2.1(@types/node@17.0.12)(sass@1.59.3)
-      vite-node: 0.29.4(@types/node@17.0.12)(sass@1.64.2)
+      vite: 4.2.1(@types/node@17.0.12)(sass@1.64.2)
+      vite-node: 0.29.4(@types/node@17.0.12)(sass@1.59.3)
       why-is-node-running: 2.2.2
     transitivePeerDependencies:
       - less
-- 
GitLab