Titan Engine

Integrating with Glide Data Grid

While Titan Engine is UI-agnostic, it was architected from the ground up to pair flawlessly with Glide Data Grid. Together, they provide Excel-level performance in a standard web browser.

The Architecture Match

Glide Data Grid expects you to provide a `getCellContent` callback that fires rapidly (often at 60fps while scrolling). If this callback triggers heavy JS calculations, the scroll frame drops.

Titan solves this through Zero-Copy Memory Access. When Glide calls `getCellContent`, Titan immediately reads the cached computed state directly from WebAssembly linear memory without executing any formula logic.

Tutorial: The Integration Loop

Here is the standard pattern for marrying the two tools using React:

import React, { useState, useEffect, useCallback, useRef } from 'react';
import { DataEditor, GridCellKind } from '@glideapps/glide-data-grid';
import { initTitan } from 'titan-engine';

export default function Spreadsheet() {
    const [engine, setEngine] = useState(null);
    const [sheet, setSheet] = useState(null);
    
    // We use a trigger to force React to re-render Glide when WASM recalculates
    const [updateTrigger, setUpdateTrigger] = useState(0);

    // 1. Initialize Titan on Mount
    useEffect(() => {
        initTitan().then(Titan => {
            const e = new Titan();
            const s = e.addSheet("Sheet1");
            
            // Listen for calculation cycle completions
            e.onCellsChanged((changes) => {
                setUpdateTrigger(prev => prev + 1);
            });
            
            setEngine(e);
            setSheet(s);
        });
    }, []);

    // 2. Feed Data to Glide
    const getCellContent = useCallback(([col, row]) => {
        if (!sheet) return { kind: GridCellKind.Text, displayData: "", data: "" };
        
        // Fast O(1) read from WASM memory boundary (supports {row, col} format)
        const cell = sheet.get({ row, col });
        
        return {
            kind: GridCellKind.Text,
            allowOverlay: true,
            displayData: cell.display.toString(),
            data: cell.display.toString(),
        };
    }, [sheet, updateTrigger]);

    // 3. Send Edits to Titan via Debounced Batching
    const editQueue = useRef([]);
    const editTimeout = useRef(null);

    const onCellEdited = useCallback((cell, newValue) => {
        const [col, row] = cell;
        
        // Queue the edit
        editQueue.current.push({ 
            sheet: sheet.id, 
            cell: {row, col}, 
            value: newValue.data 
        });
        
        // Debounce to batch multiple rapid edits (e.g. Pasting)
        if (editTimeout.current) clearTimeout(editTimeout.current);
        editTimeout.current = setTimeout(() => {
            engine.setCells(editQueue.current);
            editQueue.current = [];
        }, 10);
    }, [engine, sheet]);

    if (!sheet) return 
Loading Engine...
; return ( <DataEditor columns={[{ title: "A" }, { title: "B" }, { title: "C" }]} rows={100} getCellContent={getCellContent} onCellEdited={onCellEdited} /> ); }
arrow_back Getting Started Next: Formulas arrow_forward