/** An RDF term: named node (URI), blank node, or literal */ type RdfTerm = { termType: 'NamedNode'; value: string; } | { termType: 'BlankNode'; value: string; } | { termType: 'Literal'; value: string; datatype?: string; language?: string; }; /** A single RDF triple/quad */ interface RdfTriple { subject: string; predicate: string; object: string; /** Optional: datatype URI for literal objects */ datatype?: string; /** Optional: language tag for literal objects */ language?: string; /** Optional: graph name for quads */ graph?: string; } /** An RDF value (literal) attached to a node as a property */ interface RdfValue { value: string; datatype?: string; language?: string; /** Metadata annotations from collapsed reification statements */ annotations?: PropertyAnnotation[]; } /** Metadata from a collapsed reified statement attached to a property */ interface PropertyAnnotation { predicate: string; value: string; datatype?: string; } /** A node in the visual graph (represents an RDF subject/object URI or blank node) */ interface GraphNode { /** URI or blank node ID — stable across updates */ id: string; /** rdf:type values (full URIs) */ types: string[]; /** Resolved display label (depends on label mode) */ label: string; /** Literal properties: predicate URI → values */ properties: Map; /** Resolved image URL for avatar rendering (null if none found) */ imageUrl: string | null; /** Extracted metadata properties (provenance, timestamps, etc.) */ metadata: Map; /** Number of edges connected to this node (in + out) */ degree: number; /** Whether this is a boundary node (has hidden neighbors in focus mode) */ isBoundary: boolean; /** Optional risk/threat score for visual emphasis (set by application code) */ riskScore?: number; /** Whether this node is in the top-N risk tier (set by application code) */ isHighRisk?: boolean; /** Optional size multiplier for featured/focal nodes (set by application code) */ sizeMultiplier?: number; /** Resolved provenance info (set by ProvenanceResolver) */ provenance?: ProvenanceInfo; } /** Provenance information for a graph node */ interface ProvenanceInfo { /** Data source URIs that contributed to this node's data */ sources: string[]; /** Human-readable names for the data sources */ sourceNames: string[]; /** ISO timestamp of when this data was generated */ generatedAt?: string; /** URI of the agent/model that generated this data */ generatedBy?: string; /** Human-readable name of the generating agent */ generatedByName?: string; /** Cryptographic content hash for data integrity */ contentHash?: string; /** DKG Uniform Asset Locator */ ual?: string; /** Blockchain anchoring info */ blockchainAnchor?: { chain?: string; txHash?: string; blockNumber?: number; }; } /** An edge in the visual graph (represents an RDF triple with URI/bnode object) */ interface GraphEdge { /** Deterministic ID: `${subject}\0${predicate}\0${object}` */ id: string; /** Source node URI */ source: string; /** Target node URI */ target: string; /** Predicate URI */ predicate: string; /** Resolved display label (depends on label mode) */ label: string; } /** Set of changes from an incremental update */ interface ChangeSet { addedNodes: string[]; removedNodes: string[]; addedEdges: string[]; removedEdges: string[]; modifiedNodes: string[]; } /** Prefix map: prefix string → namespace URI */ type PrefixMap = Record; type LabelMode = 'strict' | 'humanized'; interface LabelConfig { /** Predicates to check for display labels, in priority order */ predicates?: string[]; } interface HexagonConfig { /** Base hexagon radius in pixels */ baseSize?: number; /** Minimum hexagon radius */ minSize?: number; /** Maximum hexagon radius */ maxSize?: number; /** Whether hexagon size scales with node degree */ scaleWithDegree?: boolean; /** Predicates to check for image URLs (direct or via intermediate node) */ imagePredicates?: string[]; /** Predicate to follow on intermediate image nodes to get the actual URL */ imageUrlPredicate?: string; /** * RDF type URIs (full or compact) that should render as simple filled circles * instead of hexagons. Much faster to draw — use for high-count, low-priority * node types like SentimentAnalysis, ImageObject, Keyword, etc. */ circleTypes?: string[]; } interface StyleConfig { /** Per-node colors keyed by node URI — highest priority, wins over all other rules */ nodeColors?: Record; /** Per rdf:type class colors */ classColors?: Record; /** Per namespace prefix colors (applies to nodes whose types fall in that namespace) */ namespaceColors?: Record; /** Per predicate edge colors */ predicateColors?: Record; /** Enable subtle radial gradient on nodes */ gradient?: boolean; /** Gradient intensity (0.0 = flat, 1.0 = strong gradient). Default: 0.3 */ gradientIntensity?: number; /** Default node color */ defaultNodeColor?: string; /** Default edge color */ defaultEdgeColor?: string; /** Edge width */ edgeWidth?: number; /** Edge arrow size (0 = no arrows) */ edgeArrowSize?: number; /** Node border width */ borderWidth?: number; /** Font family for labels */ fontFamily?: string; /** Font size for labels */ fontSize?: number; } interface FocusConfig { /** URI of the initial focal node. If null, auto-selects highest-degree node. */ focalNode?: string | null; /** Number of hops from focal node to include. Default: 2 */ hops?: number; /** Maximum number of nodes to render. Default: 200 */ maxNodes?: number; /** Whether clicking a boundary node expands its neighborhood. Default: true */ expandOnClick?: boolean; } interface ReificationPattern { /** rdf:type of the reification statement node */ statementType: string; /** Predicate linking statement to the reified subject */ subjectPredicate: string; /** Predicate linking statement to the reified predicate */ predicatePredicate: string; /** Predicate linking statement to the reified object/value */ objectPredicate: string; } interface ReificationConfig { /** Enable reification collapsing. Default: false */ enabled?: boolean; /** Patterns to detect. Ships with standard rdf:Statement pattern. */ patterns?: ReificationPattern[]; } interface MetadataConfig { /** Predicates whose values are treated as metadata (shown in panel, not as edges) */ predicates?: string[]; } /** Full configuration for the visualization */ interface RdfGraphVizConfig { /** Label display mode */ labelMode?: LabelMode; /** Label resolution config */ labels?: LabelConfig; /** Hexagon rendering config */ hexagon?: HexagonConfig; /** Style/color config */ style?: StyleConfig; /** Focus/filter config for large graphs */ focus?: FocusConfig; /** Reification collapsing config */ reification?: ReificationConfig; /** Metadata extraction config */ metadata?: MetadataConfig; /** Known namespace prefixes */ prefixes?: PrefixMap; /** * Rendering backend: '2d' (Canvas, default) or '3d' (WebGL/Three.js). * 3D mode requires `3d-force-graph` and `three` as peer dependencies. */ renderer?: '2d' | '3d'; /** Disable automatic zoomToFit when the force simulation settles. */ autoFitDisabled?: boolean; } type GraphEventType = 'node:click' | 'node:hover' | 'node:unhover' | 'edge:click' | 'edge:hover' | 'edge:unhover' | 'background:click' | 'focus:change' | 'data:change' | 'temporal:change'; interface GraphEventMap { 'node:click': GraphNode; 'node:hover': GraphNode; 'node:unhover': GraphNode; 'edge:click': GraphEdge; 'edge:hover': GraphEdge; 'edge:unhover': GraphEdge; 'background:click': { x: number; y: number; }; 'focus:change': { focalNode: string | null; visibleNodes: number; }; 'data:change': ChangeSet; 'temporal:change': { cursor: Date; visibleCount: number; totalDated: number; }; } type GraphEventHandler = (data: GraphEventMap[T]) => void; /** * A single SPARQL result binding row. * Keys are variable names (without ?), values are RDF term strings. */ type SparqlBinding = Record; /** Result of a SPARQL SELECT query */ interface SparqlSelectResult { variables: string[]; bindings: SparqlBinding[]; } /** Result of a SPARQL CONSTRUCT/DESCRIBE query — just triples */ interface SparqlConstructResult { triples: RdfTriple[]; } /** * Abstract data source for the graph visualizer. * * Implementations connect to different knowledge graph backends: * - OxigraphSource: In-browser WASM store (dev/demo) * - RemoteSparqlSource: Remote SPARQL endpoint (Blazegraph, GraphDB, DKG) * * The visualizer calls these methods to load and query graph data, * keeping the rendering layer decoupled from the storage layer. */ interface GraphDataSource { /** Human-readable name for this data source */ readonly name: string; /** * Load RDF data into the store (N-Triples string). * For remote sources, this may be a no-op or trigger an import. */ loadNTriples(data: string): Promise; /** * Execute a SPARQL SELECT query. * Returns variable bindings as plain strings. */ select(sparql: string): Promise; /** * Execute a SPARQL CONSTRUCT query. * Returns an array of RdfTriple objects ready for the visualizer. */ construct(sparql: string): Promise; /** * Get the total triple count in the store. */ tripleCount(): Promise; /** * Check if the source is ready / connected. */ isReady(): Promise; } /** * Subject-centric RDF graph model for visualization. * * - Literal objects → stored as properties on the subject node * - URI/blank node objects → stored as edges between nodes * - rdf:type → stored in node.types, not as an edge * * Supports incremental add/remove with stable node and edge IDs. * * Maintains adjacency indexes (_outEdges, _inEdges) for O(degree) edge * lookups instead of O(E) full scans. These are used by FocusFilter BFS, * ReificationCollapser, and ViewConfig application on the render hot path. */ declare class GraphModel { readonly nodes: Map; readonly edges: Map; prefixes: PrefixMap; /** * Stores triples in canonical form — subject, predicate, and (when the * object is a resource) object are `cleanUri`-normalised at ingress so * downstream consumers and lookup paths (e.g. `removeTriples`, * reification mirrors, diff exporters) all operate on a single * representation. Literal objects are kept verbatim so quoting, * datatypes, and language tags survive the round-trip. */ private _triples; /** Set of predicate URIs treated as metadata (not rendered as edges) */ private _metadataPredicates; /** Adjacency index: nodeId → Set of edge IDs originating from this node */ private _outEdges; /** Adjacency index: nodeId → Set of edge IDs pointing to this node */ private _inEdges; /** Knowledge Asset groups: KA URI → Set of member node IDs */ readonly kaGroups: Map>; /** Predicate used for KA membership (set via setKaMembershipPredicate) */ private _kaMembershipPredicate; constructor(metadataPredicates?: string[]); /** Get all stored triples */ get triples(): readonly RdfTriple[]; /** Set the predicate used for Knowledge Asset membership grouping */ setKaMembershipPredicate(predicate: string | null): void; /** Get or create a node */ private ensureNode; /** Ensure adjacency sets exist for a node */ private ensureAdjacency; /** Add a single triple to the model */ addTriple(triple: RdfTriple): void; /** Add multiple triples and return the changeset */ addTriples(triples: RdfTriple[]): ChangeSet; /** Remove triples matching the given criteria and return changeset */ removeTriples(triples: RdfTriple[]): ChangeSet; /** Get a node by ID */ getNode(id: string): GraphNode | undefined; /** Get all edges originating from a node — O(degree) via adjacency index */ getEdgesFrom(id: string): GraphEdge[]; /** Get all edges pointing to a node — O(degree) via adjacency index */ getEdgesTo(id: string): GraphEdge[]; /** Get all neighbor node IDs (both directions) — O(degree) via adjacency index */ getNeighborIds(id: string): Set; /** Get the node with the highest degree */ getHighestDegreeNode(): GraphNode | null; /** Clear all data */ clear(): void; /** Total number of triples */ get tripleCount(): number; } /** * Color palette system for the graph visualizer. * * A palette provides a complete, cohesive set of colors for the entire * visualization — surfaces, text, accents, semantic colors, and graph-specific * colors. Developers can use a built-in preset or supply a custom palette. */ interface ColorPalette { name: string; background: string; surface: string; surfaceBorder: string; textPrimary: string; textSecondary: string; textMuted: string; primary: string; primaryMuted: string; danger: string; warning: string; safe: string; info: string; edgeColor: string; edgeLabel: string; particleColor: string; focalGlow: string; nodeColors: string[]; } declare const PALETTE_DARK: ColorPalette; declare const PALETTE_MIDNIGHT: ColorPalette; declare const PALETTE_CYBERPUNK: ColorPalette; declare const PALETTE_LIGHT: ColorPalette; /** All built-in palettes indexed by name */ declare const PALETTES: Record; /** * Resolve a palette from a name string or custom object, with optional overrides. * Falls back to 'dark' if the name is not found. */ declare function resolvePalette(palette?: string | ColorPalette, overrides?: Partial): ColorPalette; /** * Inject palette colors as CSS custom properties on a container element. * Demo UIs can reference these as var(--gv-primary), etc. */ declare function injectPaletteCssVars(container: HTMLElement, palette: ColorPalette): void; /** * Configuration for temporal filtering. */ interface TemporalConfig { /** Enable the temporal timeline. Default: false */ enabled: boolean; /** Property short names to scan for dates (checked across known namespaces). * Default: ['dateCreated'] */ dateProperties?: string[]; /** Whether to show nodes that have no date property. Default: true */ showUndated?: boolean; /** Auto-play speed in ms per step. Default: 200 */ playSpeed?: number; /** Step granularity for playback. Default: 'day' */ stepSize?: 'hour' | 'day' | 'week' | 'month'; } /** * Temporal filter: scans nodes for date properties, manages a progressive * time cursor, and returns the set of node IDs visible up to that cursor. * * Usage: * filter.scan(model); * filter.setCursor(someDate); * const visible = filter.getVisibleNodeIds(); // nodes with date <= cursor */ declare class TemporalFilter { private _nodeDates; private _dateRange; private _cursor; private _dateProperties; private _showUndated; constructor(config?: Partial); /** Scan all nodes in the model for date properties. Call after data ingestion. */ scan(model: GraphModel): void; /** Get the global date range [earliest, latest], or null if no dates found. */ get dateRange(): [Date, Date] | null; /** Get the current cursor position. */ get cursor(): Date | null; /** Number of nodes that have a date assigned. */ get datedNodeCount(): number; /** Whether to show nodes without date properties. */ get showUndated(): boolean; set showUndated(value: boolean); /** Set the cursor (cutoff date). Nodes with date <= cursor are visible. */ setCursor(date: Date): void; /** Get the date for a specific node, or null if undated. */ getNodeDate(nodeId: string): Date | null; /** * Get the set of node IDs visible at the current cursor position. * - Dated nodes: visible if date <= cursor * - Undated nodes: visible if showUndated is true * * If no date range was found (no dated nodes), returns null * (meaning: don't filter, show everything). */ getVisibleNodeIds(allNodeIds: Iterable): Set | null; /** * Compute histogram buckets for the date distribution. * Returns an array of { date: Date, count: number } entries. */ computeHistogram(bucketCount?: number): Array<{ date: Date; count: number; }>; /** Extract the earliest date from a node's properties across known namespaces. */ private _extractDate; } /** Visual configuration for a single node type */ interface NodeTypeConfig { color?: string; shape?: 'hexagon' | 'circle'; /** Icon URL or data URI — assigned as imageUrl on matching nodes */ icon?: string; /** Static size multiplier for all nodes of this type */ sizeMultiplier?: number; } /** Focal entity configuration */ interface FocalConfig { /** URI of the focal entity (checked across namespace variants) */ uri: string; /** Image URL for the focal entity */ image?: string; /** Size multiplier (default 1.5) */ sizeMultiplier?: number; } /** Highlight / risk rule configuration */ interface HighlightConfig { /** Property short name that drives visual emphasis (checked across namespaces) */ property: string; /** Where to find the property: on the node itself, or on a linked entity */ source?: 'self' | 'linked'; /** Predicate short name to follow when source='linked' (e.g., 'hasSentiment') */ linkedVia?: string; /** Absolute value above this threshold = highlighted */ threshold: number; /** Border color for highlighted nodes */ color: string; /** How many top-scoring nodes get the size boost (default 100) */ topN?: number; /** * Size multiplier for top-N nodes. * If sizeMin/sizeMax are set, this is ignored (continuous scaling is used). * Otherwise this is a flat multiplier applied to all top-N nodes (default 2). */ sizeMultiplier?: number; /** Minimum sizeMultiplier for continuous scaling (lowest-risk in top N). Default: 1.0 */ sizeMin?: number; /** Maximum sizeMultiplier for continuous scaling (highest-risk in top N). Default: 3.0 */ sizeMax?: number; /** * Invert the scoring: treat LOW values as high risk. * Useful when the property represents a "safety" signal (e.g., sentimentScore) * where 0.0 = dangerous and 1.0 = safe. * Default: false */ invert?: boolean; } /** Size-by rule: scale node size based on a property */ interface SizeByConfig { /** Property short name (e.g., 'totalInteractions') */ property: string; /** Scale function (default 'log') */ scale?: 'linear' | 'log'; } /** Icon mapping: assign icons to posts by platform edge */ interface PlatformIconConfig { /** Map of platform ID (last path segment of platform URI) to icon URL/data URI */ icons: Record; /** URL fallback patterns: map of URL substring to platform key */ urlFallbacks?: Record; } /** Configuration for a single tooltip field */ interface TooltipFieldConfig { /** Display label in the tooltip */ label: string; /** Property short name to display (checked across known namespaces) */ property: string; /** Where to find the property: directly on the node ('self') or on a linked entity */ source?: 'self' | 'linked'; /** Predicate short name to follow when source='linked' */ linkedVia?: string; /** Display format: 'text' (default), 'number', 'date' */ format?: 'text' | 'number' | 'date'; } /** Tooltip configuration */ interface TooltipConfig { /** * Properties to try for the tooltip title, in priority order. * Each entry is a short name checked across known namespaces. * Falls back to the node's resolved label if none match. * * @example ["text", "name", "title"] */ titleProperties?: string[]; /** * Template for the tooltip subtitle line. * Supports {property} placeholders (short names). * Special tokens: {platform}, {author}, {date}, {type} * * @example "{platform} · {author} · {date}" */ subtitleTemplate?: string; /** Max characters for the title before truncation. Default: 60 */ titleMaxLength?: number; /** Additional fields to show in the tooltip */ fields?: TooltipFieldConfig[]; } /** Animation configuration for visual liveliness */ interface AnimationConfig { /** Enable link particles flowing along edges. Default: false */ linkParticles?: boolean; /** Number of particles per link. Default: 1 */ linkParticleCount?: number; /** Particle speed (0-1 range, fraction of link length per frame). Default: 0.005 */ linkParticleSpeed?: number; /** Particle color. Default: 'rgba(100,150,255,0.6)' */ linkParticleColor?: string; /** Particle width in pixels. Default: 1.5 */ linkParticleWidth?: number; /** Keep the force simulation slightly warm so nodes gently drift. Default: false */ drift?: boolean; /** Alpha target for the warm simulation (0-0.1 range). Default: 0.008 */ driftAlpha?: number; /** Enable breathing/pulse animation on high-risk nodes. Default: false */ riskPulse?: boolean; /** Highlight edges of hovered node with faster, brighter particles. Default: false */ hoverTrace?: boolean; /** Fade-in nodes/edges on initial load. Default: false */ fadeIn?: boolean; } /** Trust visualization configuration */ interface TrustConfig { /** Enable trust indicators. Default: false */ enabled: boolean; /** Minimum distinct sources for "verified" visual treatment. Default: 2 */ minSources?: number; /** Show source count badge on nodes. Default: true */ showBadge?: boolean; /** Visual style for multi-source trust: 'border' | 'opacity' | 'glow'. Default: 'border' */ style?: 'opacity' | 'border' | 'glow'; } /** Knowledge Asset boundary visualization configuration */ interface KnowledgeAssetConfig { /** Enable KA boundary rendering. Default: false */ enabled: boolean; /** Predicate linking a node to its Knowledge Asset. Default: 'dkg:partOfAsset' */ membershipPredicate?: string; /** Show convex hull boundaries around KA groups. Default: true */ showBoundaries?: boolean; /** Boundary fill opacity (0-1). Default: 0.06 */ boundaryOpacity?: number; } /** * Declarative view configuration for the graph visualizer. * * Controls what nodes look like, which are important, and how they're sized — * all without writing code. The same graph data can be visualized differently * by swapping view configs. */ interface ViewConfig { /** Human-readable name for this view */ name: string; /** Visual rules per RDF type (compact or full URI) */ nodeTypes?: Record; /** Optional focal entity (rendered large, always on top) */ focal?: FocalConfig; /** Highlight rule: which property drives risk/importance coloring */ highlight?: HighlightConfig; /** Size-by rule: scale nodes by a numeric property */ sizeBy?: SizeByConfig; /** RDF type short names rendered as circles instead of hexagons */ circleTypes?: string[]; /** Platform icon mapping for SocialMediaPosting nodes */ platformIcons?: PlatformIconConfig; /** Tooltip configuration for hover cards */ tooltip?: TooltipConfig; /** Animation configuration for visual liveliness */ animation?: AnimationConfig; /** Color palette: preset name ('dark', 'midnight', 'cyberpunk', 'light') or custom palette object */ palette?: string | ColorPalette; /** Overrides for individual palette colors (merged on top of base) */ paletteOverrides?: Partial; /** Trust visualization based on multi-source provenance */ trust?: TrustConfig; /** Knowledge Asset boundary visualization */ knowledgeAssets?: KnowledgeAssetConfig; /** Temporal timeline configuration */ temporal?: TemporalConfig; /** Default SPARQL CONSTRUCT query for this view */ defaultSparql?: string; } /** * Apply a ViewConfig to a loaded graph model. * * Sets riskScore, isHighRisk, sizeMultiplier, and imageUrl on nodes * based on the declarative rules in the config. * * Call this AFTER loading triples into the model, BEFORE refresh(). */ declare function applyViewConfig(config: ViewConfig, model: GraphModel): void; /** * DOM-based timeline overlay rendered inside the visualization container. * * Shows a single progressive slider: drag right to reveal more of the graph * chronologically. Includes play/pause, date labels, visible node count, * and a mini histogram showing node density over time. */ declare class TimelineOverlay { private _container; private _filter; private _config; private _root; private _slider; private _dateLabel; private _countLabel; private _playBtn; private _histCanvas; private _startLabel; private _endLabel; private _playInterval; private _isPlaying; private _onChange; constructor(container: HTMLElement, filter: TemporalFilter, config: TemporalConfig); /** Set callback for cursor changes */ onChange(fn: (cursor: Date, visibleCount: number) => void): void; /** Build and attach the overlay DOM. Call after filter.scan(). */ mount(): void; /** Remove the overlay from the DOM */ unmount(): void; /** Whether the overlay is currently mounted */ get mounted(): boolean; /** Update the overlay after data changes (re-scan, redraw histogram) */ refresh(): void; /** Start auto-play from current position */ play(): void; /** Pause auto-play */ pause(): void; /** Set the slider to a specific date programmatically */ setCursor(date: Date): void; private _buildHTML; private _onSliderInput; private _updateDateLabel; /** Update the visible count badge (called externally after render) */ updateCount(count: number): void; private _togglePlay; private _getStepMs; private _drawHistogram; private _formatDateShort; private _formatDateFull; private _styleId; private _injectStyles; } /** * Manages namespace prefix ↔ URI mappings for compacting and expanding URIs. */ declare class PrefixManager { private _prefixes; /** Reverse map: namespace URI → prefix */ private _reverse; constructor(userPrefixes?: PrefixMap); /** Register a new prefix */ addPrefix(prefix: string, namespace: string): void; /** Merge in multiple prefixes */ addPrefixes(prefixes: PrefixMap): void; /** Get the namespace URI for a prefix */ getNamespace(prefix: string): string | undefined; /** Get the prefix for a namespace URI */ getPrefix(namespace: string): string | undefined; /** * Compact a full URI to prefixed form (e.g., "https://schema.org/name" → "schema:name"). * Returns null if no matching prefix is found. */ compact(uri: string): string | null; /** * Expand a prefixed term to a full URI (e.g., "schema:name" → "https://schema.org/name"). * Returns the input unchanged if it's already a full URI or no prefix matches. */ expand(term: string): string; /** * Extract a short, human-readable local name from a URI. * * Strategy, in priority order: * 1. Part after the last `#` (RDF fragment: http://ex.org/ns#Foo → Foo) * 2. Part after the last `/` (HTTP path: http://ex.org/foo/Bar → Bar) * 3. If the URI contains URL-encoded slashes (%2F), decode them and * take the basename. This handles URIs like * `urn:dkg:code:file:packages%2Fnode-ui%2Fsrc%2Fui%2FApp.tsx`, * which previously returned the entire URI. * 4. Part after the last `:` (URN tail: urn:dkg:task:my-slug → my-slug) * 5. The URI itself (last resort). */ static localName(uri: string): string; /** Get all registered prefixes */ get prefixes(): PrefixMap; } /** * Resolves colors for nodes and edges based on configurable rules. * * When a ColorPalette is provided, it drives default colors: * - defaultNodeColor → palette.primary * - defaultEdgeColor → palette.edgeColor * - Label/text colors → palette.textPrimary/textSecondary * * Priority (highest first): * 1. Per-class color (matching rdf:type) * 2. Per-namespace color (matching namespace of first rdf:type) * 3. Default color (from palette or config) */ declare class StyleEngine { private _config; private _prefixManager; private _palette; private _hasExplicitDefaultNodeColor; private _hasExplicitDefaultEdgeColor; constructor(config: StyleConfig | undefined, prefixManager: PrefixManager, palette?: ColorPalette); /** The active color palette */ get palette(): ColorPalette; /** Update the active palette (recalculates defaults not explicitly set in config) */ setPalette(palette: ColorPalette): void; get config(): Readonly>; /** Update per-node color overrides (merges with existing) */ setNodeColors(colors: Record): void; /** Get the fill color for a node */ getNodeColor(node: GraphNode): string; /** Get the color for an edge */ getEdgeColor(edge: GraphEdge): string; /** Get border color (slightly lighter than fill) */ getBorderColor(fillColor: string): string; /** Get gradient center color (lighter) */ getGradientCenter(fillColor: string): string; } /** * Main entry point for the RDF Graph Visualization library. * * @example * ```typescript * const viz = new RdfGraphViz(document.getElementById('graph')!, { * labelMode: 'humanized', * style: { classColors: { 'schema:Person': '#7C3AED' } }, * focus: { hops: 2, maxNodes: 200 }, * }); * * await viz.loadNTriples(ntriplesString); * viz.on('node:click', (node) => console.log(node)); * ``` */ declare class RdfGraphViz { private _model; private _prefixManager; private _labelResolver; private _styleEngine; private _hexPainter; private _focusFilter; private _reificationCollapser; private _metadataExtractor; private _events; private _renderer; private _config; private _collapsedNodeIds; private _rendererReady; private _container; private _temporalFilter; private _timelineOverlay; private _renderQueued; private _autoFitDisabled; constructor(container: HTMLElement, config?: RdfGraphVizConfig); /** Load N-Triples or N-Quads string */ loadNTriples(input: string): Promise; /** Load N-Quads string */ loadNQuads(input: string): Promise; /** Load Turtle string */ loadTurtle(input: string): Promise; /** Load JSON-LD (object or string) */ loadJsonLd(input: Record | string): Promise; /** Load raw triple array (synchronous — no parsing needed) */ loadTriples(input: Array): void; /** * Load data from a GraphDataSource using a SPARQL CONSTRUCT query. * * This is the recommended way to load data from a knowledge graph. * The source can be an in-browser Oxigraph store or a remote SPARQL endpoint. * * @param source - A GraphDataSource (OxigraphSource, RemoteSparqlSource, etc.) * @param sparql - SPARQL CONSTRUCT query that returns the triples to visualize * * @example * ```typescript * const source = new OxigraphSource(); * await source.init(); * await source.loadNTriples(ntData); * * await viz.loadFromSource(source, ` * CONSTRUCT { ?s ?p ?o } * WHERE { * ?s a ; * ?p ?o . * } LIMIT 5000 * `); * ``` */ loadFromSource(source: GraphDataSource, sparql: string): Promise; /** * Execute a SPARQL SELECT query against a data source. * Returns raw bindings — useful for analytics, counts, and lookups * without loading triples into the graph model. */ querySource(source: GraphDataSource, sparql: string): Promise; /** Add triples to the existing graph */ addTriples(triples: RdfTriple[]): ChangeSet; /** Remove triples from the graph */ removeTriples(triples: RdfTriple[]): ChangeSet; /** Focus on a specific node with N-hop expansion */ focus(nodeId: string, hops?: number): void; /** Recenter camera on a node without changing focus filter state. */ centerOnNode(nodeId: string, opts?: { durationMs?: number; zoomLevel?: number; }): void; /** Expand a boundary node's neighborhood */ expandNode(nodeId: string): void; /** Show all nodes (disable focus filter) */ showAll(): void; /** Get the temporal filter (for advanced usage) */ get temporalFilter(): TemporalFilter; /** Get the timeline overlay (for advanced usage, null if not enabled) */ get timelineOverlay(): TimelineOverlay | null; /** Set the temporal cursor: only show nodes with dates up to this point */ setTimeCursor(date: Date): void; /** Get the date range of nodes in the graph */ getDateRange(): [Date, Date] | null; /** Start timeline playback */ playTimeline(): void; /** Pause timeline playback */ pauseTimeline(): void; /** Count visible nodes after last render (for event payloads) */ private _lastVisibleCount; /** Fit all visible nodes in view */ zoomToFit(padding?: number): void; /** Prevent the renderer from automatically calling zoomToFit when the simulation settles. */ set autoFitDisabled(value: boolean); /** Get current label mode */ get labelMode(): LabelMode; /** Set label mode and re-render */ setLabelMode(mode: LabelMode): void; /** Subscribe to a graph event */ on(event: T, handler: GraphEventHandler): () => void; /** Unsubscribe from a graph event */ off(event: T, handler: GraphEventHandler): void; /** Get a node by ID */ getNode(id: string): GraphNode | undefined; /** Get all edges from a node */ getEdgesFrom(id: string): GraphEdge[]; /** Get all edges to a node */ getEdgesTo(id: string): GraphEdge[]; /** Get the underlying graph model (for advanced usage) */ get model(): GraphModel; /** Get the style engine (for dynamic per-node color overrides) */ get styleEngine(): StyleEngine; /** Get the prefix manager (for compact/expand operations) */ get prefixes(): PrefixManager; /** Saved visual state for highlighted nodes, used by clearHighlight() to revert */ private _highlightState; /** * Visually emphasize a set of nodes without modifying underlying data. * Typically used to highlight SPARQL query results in the current view. * * @example * ```typescript * const result = await viz.querySource(kg, ` * SELECT ?post WHERE { * ?post ?risk . * FILTER(?risk > 50) * } * `); * viz.highlightNodes(result.bindings.map(b => b.post)); * ``` */ highlightNodes(nodeIds: string[]): void; /** Revert all highlighted nodes to their original visual state */ clearHighlight(): void; /** * Export the current visualization as a PNG image. * Captures the canvas content from the active renderer backend. */ exportImage(): Promise; /** * Export the current graph model as N-Triples string. * Serializes all triples currently loaded in the visualization. */ exportTriples(): string; /** * Apply a ViewConfig to the current graph. * * Sets focal entity styling, platform icons, risk/highlight scores, * and node type icons based on the declarative config. * Automatically calls refresh() to re-render. * * @example * ```typescript * await viz.loadFromSource(kg, sparql); * viz.applyViewConfig(config); * ``` */ applyView(config: ViewConfig): void; /** Force a visual re-render (call after modifying node properties externally) */ refresh(): void; /** Destroy the visualization and clean up resources */ destroy(): void; /** Ingest triples, resolve labels/images, and render */ private _ingest; /** Post-ingestion processing: resolve images, labels, collapse, render */ private _postIngest; /** Render with current focus filter + temporal filter state */ private _renderCurrent; } /** * In-browser knowledge graph powered by Oxigraph WASM. * * Provides a full SPARQL 1.1 store that runs entirely in the browser — * perfect for development, demos, and offline usage. * * @example * ```typescript * const source = new OxigraphSource(); * await source.init(); * await source.loadNTriples(ntriplesString); * * const result = await source.construct(` * CONSTRUCT { ?s ?p ?o } * WHERE { ?s a ; ?p ?o } * LIMIT 1000 * `); * * viz.loadTriples(result.triples); * ``` */ declare class OxigraphSource implements GraphDataSource { readonly name = "Oxigraph (in-browser)"; private _store; private _oxigraph; /** * Initialize the Oxigraph WASM module. * Must be called before any other method. * * @param wasmUrl - Optional URL to the `web_bg.wasm` file. * In Vite/browser environments, pass this explicitly to avoid * bundler issues with WASM file resolution: * ``` * await source.init('/data/oxigraph.wasm'); * ``` * In Node.js, this can be omitted. */ init(wasmUrl?: string): Promise; private ensureReady; loadNTriples(data: string): Promise; loadTurtle(data: string): Promise; select(sparql: string): Promise; construct(sparql: string): Promise; tripleCount(): Promise; isReady(): Promise; /** Get the raw Oxigraph store for advanced usage */ get store(): any; /** Convert an Oxigraph RDF term to a string */ private termToString; } interface RemoteSparqlConfig { /** SPARQL endpoint URL (e.g., http://localhost:9999/blazegraph/sparql) */ endpoint: string; /** Optional namespace/repository path appended to endpoint */ namespace?: string; /** Additional HTTP headers (e.g., for auth) */ headers?: Record; /** Request timeout in milliseconds (default: 30000) */ timeoutMs?: number; } /** * Remote SPARQL endpoint data source. * * Connects to any SPARQL 1.1 compatible endpoint (Blazegraph, GraphDB, * OriginTrail DKG node, Virtuoso, etc.) via HTTP. * * @example * ```typescript * const source = new RemoteSparqlSource({ * endpoint: 'http://localhost:9999/blazegraph/sparql', * namespace: 'kb', * }); * * const result = await source.construct(` * CONSTRUCT { ?s ?p ?o } * WHERE { ?s a ; ?p ?o } * LIMIT 1000 * `); * * viz.loadTriples(result.triples); * ``` */ declare class RemoteSparqlSource implements GraphDataSource { readonly name: string; private _config; constructor(config: RemoteSparqlConfig); private get endpointUrl(); loadNTriples(_data: string): Promise; select(sparql: string): Promise; construct(sparql: string): Promise; tripleCount(): Promise; isReady(): Promise; private executeQuery; /** Minimal N-Triples parser for CONSTRUCT results */ private parseNTriples; } /** * Draws hexagonal nodes on a Canvas 2D context. * Called by force-graph's nodeCanvasObject callback. * * Nodes whose rdf:type matches a `circleTypes` entry are drawn as simple * filled circles (much cheaper — no gradient, no border, no image, no label). */ declare class HexagonPainter { private _config; private _styleEngine; private _maxDegree; /** Expanded circleTypes — full URIs resolved from compact forms */ private _circleTypeSet; /** Callback to trigger graph repaint when an image finishes loading */ private _onImageLoad; /** Trust visualization style */ private _trustStyle; /** Whether to show provenance badges */ private _showBadges; constructor(config: HexagonConfig | undefined, styleEngine: StyleEngine, prefixManager?: PrefixManager); /** Check if a node should render as a simple circle */ isCircleNode(node: GraphNode): boolean; /** Set callback to trigger repaint when images load */ setImageLoadCallback(cb: () => void): void; /** Update the max degree for scaling calculations */ setMaxDegree(maxDegree: number): void; /** Set the trust visualization style */ setTrustStyle(style: 'opacity' | 'border' | 'glow' | 'none'): void; /** Enable/disable provenance badges */ setShowBadges(show: boolean): void; /** Get the radius for a node (optionally scaled by degree, boosted if has image) */ getRadius(node: GraphNode): number; /** * Paint a node onto the canvas. * Circle-type nodes get a minimal filled circle (fast path). * All others get the full hexagon treatment. * * @param pulseScale - Optional multiplier for risk pulse animation (1.0 = no pulse) * @returns the bounding radius for hit detection. */ paint(ctx: CanvasRenderingContext2D, node: GraphNode, x: number, y: number, globalScale: number, pulseScale?: number): number; /** Paint provenance badges on a node */ private _paintBadges; /** * Fast path: paint a minimal filled circle. * No gradient, no border, no image, no label — just a flat arc. */ private paintCircle; /** Paint an avatar image clipped to the hexagon shape */ private paintAvatar; /** * Resolve image URL for a node from its properties, * following indirect links if needed. * * Two resolution strategies: * 1. Direct: node has a literal property (schema:image → "https://...jpg") * 2. Indirect: node links to an image node which has the URL * (node → schema:image → ImageObject → schema:url → "https://...jpg") */ resolveImageUrl(node: GraphNode, getNode: (id: string) => GraphNode | undefined, getEdgesFrom?: (id: string) => GraphEdge[]): string | null; } /** * Typed event emitter for graph visualization events. */ declare class GraphEventEmitter { private _handlers; /** Subscribe to an event */ on(event: T, handler: GraphEventHandler): () => void; /** Unsubscribe from an event */ off(event: T, handler: GraphEventHandler): void; /** Emit an event to all registered handlers */ emit(event: T, data: GraphEventMap[T]): void; /** Remove all handlers for an event, or all handlers if no event specified */ removeAll(event?: GraphEventType): void; } /** * Abstract rendering backend for the graph visualizer. * * Implementations wrap a specific rendering engine: * - Canvas2DRenderer: force-graph (HTML5 Canvas 2D) * - WebGL3DRenderer: 3d-force-graph (Three.js/WebGL) * * The backend is deliberately "dumb" — it only puts pixels on screen. * All intelligence (graph model, focus filtering, reification collapsing, * view config application) lives in the shared subsystems above the backend. * * Advanced users can implement custom renderers (WebXR, SVG, etc.) * by implementing this interface and passing it to RdfGraphViz. */ interface RendererBackend { /** Initialize the rendering engine and attach to the container */ init(): void; /** * Render the graph with the given nodes and edges. * Preserves positions of existing nodes for smooth transitions. * * @param nodes - Visible nodes (after focus filtering) * @param edges - Visible edges (after focus filtering) * @param collapsedNodeIds - Node IDs hidden by reification collapsing */ render(nodes: Map, edges: Map, collapsedNodeIds?: Set): void; /** Focus the camera on a specific node */ centerOnNode(nodeId: string, durationMs?: number, zoomLevel?: number): void; /** Fit all visible nodes in view */ zoomToFit(padding?: number, durationMs?: number): void; /** Repaint visuals without replacing graph data/layout state */ refresh?(): void; /** Resize to fit container dimensions */ resize(): void; /** Clean up all resources */ destroy(): void; /** * Get the underlying rendering surface for export. * Returns HTMLCanvasElement for 2D, or the WebGL canvas for 3D. * Returns null if the renderer hasn't been initialized. */ getCanvas(): HTMLCanvasElement | null; /** Apply animation configuration (particles, drift, etc.) */ applyAnimation?(config: AnimationConfig): void; /** Apply a color palette (background, risk colors, etc.) */ applyPalette?(palette: ColorPalette): void; /** Prevent the renderer from automatically calling zoomToFit when the simulation settles. */ autoFitDisabled?: boolean; /** Configure Knowledge Asset boundary groups (2D only initially) */ setKaGroups?(groups: Map>, enabled: boolean, opacity?: number): void; } /** * Configuration needed to construct any renderer backend. * Passed by RdfGraphViz when creating the backend. */ interface RendererBackendConfig { container: HTMLElement; hexPainter: HexagonPainter; styleEngine: StyleEngine; events: GraphEventEmitter; } /** * 2D Canvas renderer backend using force-graph. * * Renders hexagonal nodes via HexagonPainter on an HTML5 Canvas 2D context. * Implements RendererBackend so it can be swapped with a 3D renderer. */ declare class Canvas2DRenderer implements RendererBackend { private _container; private _graph; private _hexPainter; private _styleEngine; private _events; private _currentNodes; private _positionCache; private _currentLinks; private _repaintPending; private _riskPulseEnabled; private _hoverTraceEnabled; private _hoveredNodeId; private _fadeInEnabled; private _loadTime; private _fadeInDuration; private _animFrameId; private _initialFitDone; private _autoFitDisabled; private _lastTopologyKey; private _continuousSimulation; private _fitTimeoutId; /** force-graph version compatibility guard */ private _setAlphaTarget; private _kaGroups; private _kaEnabled; private _kaBoundaryOpacity; constructor(config: RendererBackendConfig); /** Initialize the force-graph instance */ init(): void; /** * Render the graph with the given nodes and edges. * Preserves positions of existing nodes for smooth transitions. */ render(nodes: Map, edges: Map, collapsedNodeIds?: Set): void; /** Focus the camera on a specific node */ centerOnNode(nodeId: string, durationMs?: number, zoomLevel?: number): void; /** Fit all nodes in view */ zoomToFit(padding?: number, durationMs?: number): void; /** Prevent the renderer from automatically calling zoomToFit when the simulation settles. */ set autoFitDisabled(value: boolean); /** Get the underlying canvas element for export */ getCanvas(): HTMLCanvasElement | null; /** Repaint node/edge visuals without rebuilding graph data. */ refresh(): void; /** * Schedule a debounced repaint — used when images finish loading * after the simulation has cooled down. Limits the reheat to 3 * ticks so the charge force can't displace settled nodes noticeably. */ private _scheduleRepaint; /** Stop the animation loop */ private _stopAnimLoop; /** Configure Knowledge Asset boundary rendering */ setKaGroups(groups: Map>, enabled: boolean, opacity?: number): void; /** Draw convex hulls around KA groups */ private _drawKaBoundaries; /** Resize to fit container */ resize(): void; /** Clean up */ destroy(): void; /** Apply animation configuration: link particles, drift, pulse, hover trace, fade-in */ applyAnimation(config: AnimationConfig): void; /** Apply palette: update background color */ applyPalette(palette: ColorPalette): void; } /** * Resolves display labels for nodes and edges based on the current label mode. * * - "strict": Shows compact prefixed URI (e.g., "schema:Person", "prov:wasGeneratedBy") * - "humanized": Shows friendly label (e.g., "Person", "was generated by") */ declare class LabelResolver { private _mode; private _prefixManager; private _labelPredicates; constructor(mode: LabelMode, prefixManager: PrefixManager, config?: LabelConfig); get mode(): LabelMode; set mode(value: LabelMode); /** Resolve a display label for a node */ resolveNodeLabel(node: GraphNode): string; /** Resolve a display label for an edge */ resolveEdgeLabel(edge: GraphEdge): string; /** Resolve a display label for a URI */ resolveUri(uri: string): string; /** Resolve a type label (used for type badges) */ resolveTypeLabel(typeUri: string): string; /** Resolve label for a predicate (used in property lists) */ resolvePredicateLabel(predicateUri: string): string; /** * Update all labels on nodes and edges in the graph. * Call this after changing label mode or adding new data. */ updateLabels(nodes: Map, edges: Map): void; } /** * Filters a large GraphModel down to a renderable subgraph * centered around a focal node with N-hop expansion. */ declare class FocusFilter { private _config; private _visibleNodes; private _focalNode; private _enabled; constructor(config: FocusConfig | undefined); get focalNode(): string | null; get enabled(): boolean; get visibleNodeIds(): ReadonlySet; /** * Compute the visible subgraph. Call this after data changes. * Automatically enables focus mode if the graph exceeds maxNodes. */ compute(model: GraphModel): { nodes: Map; edges: Map; }; /** Change the focal node and recompute */ setFocus(nodeId: string | null): void; /** Expand a boundary node: add it as a secondary focus point */ expandNode(nodeId: string, model: GraphModel): void; /** Disable focus filtering (show all) */ disable(): void; /** Re-enable with current or new config */ enable(focalNode?: string): void; } /** * Detects and collapses reified statement nodes. * * When a node matches a reification pattern (has the right rdf:type + subject/predicate/object links), * it is removed from the visual graph. Its non-structural properties (provenance, timestamps, etc.) * are attached as annotations to the corresponding property on the reified subject node. */ declare class ReificationCollapser { private _config; constructor(config: ReificationConfig | undefined); get enabled(): boolean; /** * Process the graph model: detect reified statements, collapse them, * and attach their metadata as annotations on the original properties. * * Returns the set of node IDs that were collapsed (removed from visual rendering). */ collapse(model: GraphModel): Set; /** Detect reified statements in the model */ private detectStatements; } /** * Provides the list of predicates that should be treated as metadata * (shown in the detail panel, not rendered as graph edges). * * This is a simple config resolver — the actual separation happens in GraphModel. */ declare class MetadataExtractor { private _predicates; constructor(config?: MetadataConfig); /** Get all metadata predicate URIs */ get predicates(): string[]; /** Check if a predicate is a metadata predicate */ isMetadata(predicateUri: string): boolean; /** Add additional metadata predicates at runtime */ addPredicates(predicates: string[]): void; } /** * Resolves provenance information for graph nodes by traversing * metadata properties and following provenance edges. * * Populates `node.provenance` with: * - Data sources (URIs + human-readable names) * - Generation timestamp * - Generating agent/model * - Content hash * - UAL and blockchain anchor (when available) */ declare class ProvenanceResolver { /** * Resolve provenance for all nodes in the model. * Should be called after data is loaded and before rendering. */ resolve(model: GraphModel): void; private _resolveNodeProvenance; /** Find a value from a node's properties, checking multiple predicate URIs */ private _findValue; /** Find a value from a node's metadata, checking multiple predicate URIs */ private _findMetadataValue; /** Resolve a human-readable name for a node */ private _resolveName; } export { type AnimationConfig, Canvas2DRenderer, type ChangeSet, type ColorPalette, type FocalConfig, type FocusConfig, FocusFilter, type GraphDataSource, type GraphEdge, GraphEventEmitter, type GraphEventHandler, type GraphEventMap, type GraphEventType, GraphModel, type GraphNode, type HexagonConfig, HexagonPainter, type HighlightConfig, type KnowledgeAssetConfig, type LabelConfig, type LabelMode, LabelResolver, type MetadataConfig, MetadataExtractor, type NodeTypeConfig, OxigraphSource, PALETTES, PALETTE_CYBERPUNK, PALETTE_DARK, PALETTE_LIGHT, PALETTE_MIDNIGHT, type PlatformIconConfig, PrefixManager, type PrefixMap, type PropertyAnnotation, type ProvenanceInfo, ProvenanceResolver, RdfGraphViz, type RdfGraphVizConfig, type RdfTerm, type RdfTriple, type RdfValue, ReificationCollapser, type ReificationConfig, type ReificationPattern, type RemoteSparqlConfig, RemoteSparqlSource, type RendererBackend, type RendererBackendConfig, type SizeByConfig, type SparqlBinding, type SparqlConstructResult, type SparqlSelectResult, type StyleConfig, StyleEngine, type TemporalConfig, TemporalFilter, TimelineOverlay, type TooltipConfig, type TooltipFieldConfig, type TrustConfig, type ViewConfig, applyViewConfig, injectPaletteCssVars, resolvePalette };