A monorepo containing Vue 3 visualization components for the Pennsieve platform.
| Package | Description |
|---|---|
@pennsieve-viz/core |
Main library with visualization components (DataExplorer, UMAP, ProportionPlot, Markdown, TextViewer, AiPlotly) and DuckDB utilities |
@pennsieve-viz/tsviewer |
Timeseries data viewer component |
@pennsieve-viz/micro-ct |
OME-TIFF/TIFF viewer components for microscopy data (OmeViewer, TiffViewer) |
pennsieve-viz-monorepo/
├── packages/
│ ├── core/ # @pennsieve-viz/core - Main component library
│ │ └── src/
│ │ ├── ai-plotly/
│ │ ├── data-explorer/
│ │ ├── duckdb/
│ │ ├── markdown/
│ │ ├── proportion-plot/
│ │ ├── text-viewer/
│ │ └── umap/
│ ├── ts-viewer/ # @pennsieve-viz/tsviewer - Timeseries viewer
│ └── micro-ct/ # @pennsieve-viz/micro-ct - Micro-CT/TIFF viewers
├── pnpm-workspace.yaml
└── package.json
- Node.js >= 18
- pnpm >= 8
pnpm install# Install dependencies
pnpm install
# Start the dev server
pnpm devThe dev server runs at http://localhost:5173 (or next available port) and serves packages/core/src/App.vue as a playground for testing components.
- Start the dev server:
pnpm dev - Edit components in
packages/core/src/- changes hot-reload automatically - For changes to
tsviewerormicro-ct: rebuild the package, then refresh the browser
# Example: After editing packages/ts-viewer/src/
pnpm --filter @pennsieve-viz/tsviewer build
# Then refresh your browserWhen making changes to a dependent package (e.g., @pennsieve-viz/micro-ct or @pennsieve-viz/tsviewer), you must build the package before the changes appear in the dev server:
# Build a specific package
pnpm --filter @pennsieve-viz/micro-ct build
pnpm --filter @pennsieve-viz/tsviewer build
# Then the dev server will pick up the changes on next refreshWorkflow:
- Make changes to a package in
packages/<package-name>/src/ - Build that package:
pnpm --filter @pennsieve-viz/<package-name> build - Refresh the dev server in your browser to see changes
This is because pnpm dev only watches the core package itself. Other packages are imported from their built dist/ folders.
To add a new visualization component to @pennsieve-viz/core:
-
Create a component folder in
packages/core/src/:packages/core/src/my-component/ ├── index.ts # Exports ├── MyComponent.vue # Main component └── types.ts # TypeScript types (optional) -
Create the component (
MyComponent.vue):<script setup lang="ts"> defineProps<{ apiUrl: string }>() </script> <template> <div class="my-component"> <!-- Component content --> </div> </template>
-
Create the index export (
index.ts):export { default as MyComponent } from './MyComponent.vue'
-
Export from the core package - Add to
packages/core/src/index.ts:export * from './my-component' // Optional: Add lazy-loaded version export const MyComponentLazy = defineAsyncComponent( () => import('./my-component').then(m => m.MyComponent) )
-
Test in the playground - Import and use in
packages/core/src/App.vue:<script setup> import { MyComponent } from './my-component' </script> <template> <MyComponent :apiUrl="apiUrl" /> </template>
-
Run the dev server to test:
pnpm dev
To test a component in the dev server, use it in packages/core/src/App.vue.
Build all packages:
pnpm buildBuild a specific package:
pnpm build:core
pnpm build:tsviewerpnpm clean # Remove all dist folders
pnpm lint # Lint all packages
pnpm type-check # Type check all packagesThis monorepo uses Changesets for version management and publishing.
Initialize changesets if not already configured:
pnpm changeset init-
Create a changeset when you make changes that should be released:
pnpm changeset
Follow the prompts to select which packages changed and the type of change (patch/minor/major).
-
Version packages (updates package.json versions and changelogs):
pnpm version
-
Build and publish to npm:
pnpm release
This runs
pnpm buildfollowed bychangeset publish.
To publish a single package manually:
# Build the package
pnpm --filter @pennsieve-viz/core build
# Navigate to the package and publish
cd packages/core
npm publish --access publicEnsure you're logged in to npm:
npm loginFor scoped packages (@pennsieve-viz/*), you may need to set up organization access on npmjs.com.
Install the core package:
pnpm add @pennsieve-viz/coreFor optional viewers, install the additional packages:
pnpm add @pennsieve-viz/tsviewer # For timeseries viewer
pnpm add @pennsieve-viz/micro-ct # For micro-CT/TIFF viewersImport styles in your main entry file:
import '@pennsieve-viz/core/style.css'Import and use components from the core package:
<script setup>
import { UMAP, DataExplorer, ProportionPlot, Markdown, TextViewer, AiPlotly } from '@pennsieve-viz/core'
</script>
<template>
<UMAP :apiUrl="config.apiUrl" />
<DataExplorer :apiUrl="config.apiUrl" />
</template>The core package also provides lazy-loaded versions for tree-shaking:
<script setup>
import { UMAPLazy, DataExplorerLazy, TSViewer, OmeViewer, TiffViewer } from '@pennsieve-viz/core'
</script>Components accept an apiUrl prop that should match your environment's API domain:
<UMAP :apiUrl="config.apiUrl" />
<DataExplorer :apiUrl="config.apiUrl" />The @pennsieve-viz/tsviewer package (packages/ts-viewer/) provides a timeseries data visualization component for viewing and annotating time-based signal data.
pnpm add @pennsieve-viz/tsviewerThe tsviewer requires the following peer dependencies:
pnpm add vue@^3.2.0 pinia@^2.0.0 element-plus@^2.3.0Optional peer dependency for authentication:
pnpm add @aws-amplify/auth@^6.0.0Import styles in your main entry file:
import '@pennsieve-viz/tsviewer/style.css'Import the component and store:
import { TSViewer, useViewerStore } from '@pennsieve-viz/tsviewer'Or use the lazy-loaded version from core:
import { TSViewer } from '@pennsieve-viz/core'<script setup>
import { TSViewer, useViewerStore } from '@pennsieve-viz/tsviewer'
const viewerStore = useViewerStore()
// Configure the API endpoint
viewerStore.setViewerConfig({
timeseriesDiscoverApi: 'https://api.pennsieve.io/timeseries'
})
// Load timeseries data for a package
viewerStore.fetchAndSetActiveViewer({ packageId: 'your-package-id' })
</script>
<template>
<TSViewer
:pkg="packageData"
:is-preview="false"
:side-panel-open="false"
/>
</template>| Prop | Type | Default | Description |
|---|---|---|---|
pkg |
Object | {} |
Package metadata object |
isPreview |
Boolean | false |
When true, renders in preview mode (no toolbar) |
sidePanelOpen |
Boolean | false |
Indicates if side panel is open (affects layout) |
The useViewerStore() provides methods for managing viewer state:
const viewerStore = useViewerStore()
// Configuration
viewerStore.setViewerConfig({ timeseriesDiscoverApi: '...' })
// Load data
viewerStore.fetchAndSetActiveViewer({ packageId: '...' })
// Access channels
viewerStore.viewerChannels
viewerStore.viewerSelectedChannels
// Annotations
viewerStore.viewerAnnotations
viewerStore.createAnnotation(annotation)
viewerStore.updateAnnotation(annotation)
viewerStore.deleteAnnotation(annotation)
// Reset state
viewerStore.resetViewer()