Solved: How to Use React Three Fiber (R3F) in a Grafana Panel Plugin

I needed to use grafa for 3d visualisation and here are the steps I used to use r3f inside a panel plugin:

1: make a new panel plugin

htt ps://grafana.com/developers/plugin-tools/tutorials/build-a-panel-plugin
if you haven’t already, I find myself needing to run npm i before npm run dev

2: intall compatible versions with grafana’s react.

grafana uses r18 so fiber8 works with it
npm install three @react-three/fiber@8 @react-three/drei@9
npm install --save-dev @types/three

3: change webpack config:

official docs (htt ps://grafana.com/developers/plugin-tools/how-to-guides/extend-configurations)
add webpack.config.ts to your project root containing the following

// webpack.config.ts (Project Root)
import type { Configuration } from 'webpack';
import { merge } from 'webpack-merge';
import grafanaConfig, { Env } from './.config/webpack/webpack.config';
import path from 'path';

const config = async (env: Env): Promise<Configuration> => {
  const baseConfig = await grafanaConfig(env);

  return merge(baseConfig, {
    resolve: {
      alias: {
        // Intercepts the dev build of react-reconciler to prevent the production flag crash
        'react-reconciler': path.resolve(__dirname, 'node_modules/react-reconciler/cjs/react-reconciler.production.min.js'),
      },
    },
  });
};

export default config;

then in package.json as in the docs(htt ps://grafana.com/developers/plugin-tools/how-to-guides/extend-configurations#3-update-the-packagejson-to-use-the-new-webpack-config)

-"build": "webpack -c ./.config/webpack/webpack.config.ts --env production",
+"build": "webpack -c ./webpack.config.ts --env production",
-"dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development",
+"dev": "webpack -w -c ./webpack.config.ts --env development",

4: use fiber

then in src/components/SimplePanel.tsx

import React from 'react';
import { PanelProps } from '@grafana/data';
import { SimpleOptions } from 'types';
import { Canvas } from '@react-three/fiber';
import { CameraControls } from '@react-three/drei';

interface Props extends PanelProps<SimpleOptions> { }

export const SimplePanel: React.FC<Props> = ({ options, data, width, height, fieldConfig, id }) => {

  return (
    <div id="canvas-container" style={{ width, height, position: 'relative', overflow: 'hidden' }}>
      <Canvas>
        <directionalLight color="white" position={[0, 2, 5]} />

        <mesh position={[0, 0, 0]} onPointerOver={(e) => { e.stopPropagation() }}>
          <boxGeometry args={[1, 1, 1]} />
          <meshStandardMaterial />
        </mesh>

        <CameraControls />

      </Canvas>
    </div>
  );
};

and alhamdo li Allah everything is now working correctly:

it solves this topic which was closed automatically. @tomglenn
thanks to this topic for the start of the solution.

extra

We could even do more complex things (for the job, won’t share more)

nice! How’s your dataframe for this scene look like?

this scene is generated from JSON data as options

oh really? And what does it look like

JSON looks something like:
rooms = [{ x: 0, y: 0, w: 20, h: 30, components: [{ x: 2, y: 2, rotation: 1, model: 'electric-motor' }] }]

a room is just a boxGeometry: with side as BackSide

import { BackSide } from 'three';
...
      <mesh position={[data.width / 2, 5, data.height / 2]}>
        <boxGeometry args={[data.width, 10, data.height]} />
        <meshStandardMaterial side={BackSide} color='orange' />
      </mesh>

components:

const models: any = {
  "electric-motor": ElectricMotor,
} as const;

where ElectricMotor is r3f component made with the command
npx gltfjsx@6.5.3 ./electric-motor.glb --transform

and modified the result for webpack

// import modelUrl from './electric-motor-transformed.glb?url'
const modelUrl = new URL('./electric-motor-transformed.glb', import.meta.url).href;