Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 21 additions & 21 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 15 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@planara/react",
"version": "1.2.0",
"version": "1.3.0",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
Expand All @@ -20,6 +20,14 @@
"files": [
"dist"
],
"keywords": [
"planara",
"3d",
"react"
],
"author": "a1unade",
"license": "MIT",
"description": "React adapter for Planara",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
Expand All @@ -30,8 +38,8 @@
"check-format": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,css,md}\""
},
"dependencies": {
"@planara/core": "^3.1.0",
"@planara/types": "^1.12.0"
"@planara/core": "^3.2.1",
"@planara/types": "^1.13.0"
},
"devDependencies": {
"@eslint/js": "^9.36.0",
Expand All @@ -55,5 +63,9 @@
"peerDependencies": {
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
},
"repository": {
"type": "git",
"url": "git+https://github.com/planara/planara-react.git"
}
}
75 changes: 75 additions & 0 deletions src/components/canvas/benchmark-canvas.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React, { useEffect, useRef } from 'react';
// Core
import { createBenchmarkHub } from '@planara/core';
// Interfaces
import type { IBenchmarkApi } from '../../interfaces/benchmark-api';
// Contexts
import { useBenchmarkHubContext } from '../../contexts/benchmark-hub-context';
// Types
import type { RendererConfigInput } from '@planara/types';

interface BenchmarkCanvasProps {
className?: string;
width?: number;
height?: number;
config?: RendererConfigInput;
}

export const BenchmarkCanvas: React.FC<BenchmarkCanvasProps> = ({
className,
width = 1000,
height = 1000,
config,
}) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const { setHub } = useBenchmarkHubContext();

useEffect(() => {
if (!canvasRef.current) return;

const canvas = canvasRef.current;
const parent = canvas.parentElement;
if (!parent) return;

const benchmarkHub = createBenchmarkHub(canvas, config);

const api: IBenchmarkApi = {
run: (benchmarkConfig) => benchmarkHub.run(benchmarkConfig),
getReport: () => benchmarkHub.getReport(),
subscribeMetrics: (listener) => benchmarkHub.subscribeMetrics(listener),

resizeRenderer: () => benchmarkHub.resizeRenderer(),
start: () => benchmarkHub.start(),
stop: () => benchmarkHub.stop(),
};

setHub(api);

const handleResize = () => {
const nextWidth = parent.clientWidth;
const nextHeight = parent.clientHeight;

canvas.style.width = `${nextWidth}px`;
canvas.style.height = `${nextHeight}px`;

api.resizeRenderer();
};

handleResize();
api.start();

window.addEventListener('resize', handleResize);

return () => {
api.stop();
window.removeEventListener('resize', handleResize);

benchmarkHub.dispose();
setHub(null);
};
}, [setHub, config]);

return <canvas ref={canvasRef} className={className} width={width} height={height} />;
};

export default BenchmarkCanvas;
24 changes: 24 additions & 0 deletions src/contexts/benchmark-hub-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { createContext, useContext } from 'react';
// Interfaces
import type { IBenchmarkApi } from '../interfaces/benchmark-api';

export interface IBenchmarkContext {
hub: IBenchmarkApi | null;
setHub: (hub: IBenchmarkApi | null) => void;
}

export const BenchmarkHubContext = createContext<IBenchmarkContext | null>(null);

export const useBenchmarkHubContext = (): IBenchmarkContext => {
const context = useContext(BenchmarkHubContext);

if (!context) {
throw new Error('useBenchmarkHubContext must be used inside BenchmarkProvider');
}

return context;
};

export const useBenchmarkHub = (): IBenchmarkApi | null => {
return useBenchmarkHubContext().hub;
};
24 changes: 24 additions & 0 deletions src/hooks/use-benchmark-metrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Core
import { useEffect, useState } from 'react';
// Types
import type { BenchmarkMetrics } from '@planara/types';
// Contexts
import { useBenchmarkHub } from '../contexts/benchmark-hub-context';

export const useBenchmarkMetrics = (): BenchmarkMetrics | null => {
const hub = useBenchmarkHub();
const [metrics, setMetrics] = useState<BenchmarkMetrics | null>(null);

useEffect(() => {
if (!hub) {
setMetrics(null);
return;
}

return hub.subscribeMetrics((nextMetrics) => {
setMetrics(nextMetrics);
});
}, [hub]);

return metrics;
};
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ export { EditorCanvas } from './components/canvas/editor-canvas';
export { useEditorHub, useEditorHubContext } from './contexts/editor-hub-context';
export { useSelectionStats } from './hooks/use-selection-stats';
export { makeEditorHandlers } from './actions/button';

// Benchmark
export { BenchmarkProvider } from './providers/benchmark-provider';
export { BenchmarkCanvas } from './components/canvas/benchmark-canvas';
export { useBenchmarkHub, useBenchmarkHubContext } from './contexts/benchmark-hub-context';
export { useBenchmarkMetrics } from './hooks/use-benchmark-metrics';
20 changes: 20 additions & 0 deletions src/interfaces/benchmark-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type {
BenchmarkConfig,
BenchmarkReport,
BenchmarkRunResult,
BenchmarkMetrics,
} from '@planara/types';

export type MetricsListener = (metrics: BenchmarkMetrics | null) => void;

export interface IBenchmarkApi {
run: (config: BenchmarkConfig) => BenchmarkRunResult;

getReport: () => BenchmarkReport;

subscribeMetrics: (listener: MetricsListener) => () => void;

resizeRenderer: () => void;
start: () => void;
stop: () => void;
}
26 changes: 26 additions & 0 deletions src/providers/benchmark-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Core
import React, { useMemo, useState } from 'react';
// Interfaces
import type { IBenchmarkApi } from '../interfaces/benchmark-api';
// Contexts
import { BenchmarkHubContext } from '../contexts/benchmark-hub-context';

interface BenchmarkProviderProps {
children: React.ReactNode;
}

export const BenchmarkProvider: React.FC<BenchmarkProviderProps> = ({ children }) => {
const [hub, setHub] = useState<IBenchmarkApi | null>(null);

const value = useMemo(
() => ({
hub,
setHub,
}),
[hub],
);

return <BenchmarkHubContext.Provider value={value}>{children}</BenchmarkHubContext.Provider>;
};

export default BenchmarkProvider;
Loading