Sketch
SketchDocs
by FileKit Studio
Whiteboard SDK

Templates & Code Integration

Step-by-step beginner guide to exporting diagram templates, using normalized element JSON in code, and displaying vector diagrams with SketchViewer and SketchEditor.

When building real-world applications, you often need to save whiteboard drawings as reusable templates or embed pre-designed system architectures directly into your React or Next.js code.

This guide walks you through how to export diagrams from Sketch, understand the data format, and render diagrams in code step-by-step with live examples.


1. The Core Concept: .sketch Files vs. Template JSON

Sketch provides two distinct formats for different use cases:

FormatPurposeWhere It Is Used
.sketch FileFull Whiteboard Backup: Preserves entire board state, viewport camera, document title, background color, and grid style.Saving files to disk (diagram_*.sketch), version controlling board states, and re-importing into the editor.
Template JSONReusable Code Snippet: Auto-normalizes element coordinates so the top-left shape begins at (0, 0), stripping board-specific offsets.Hardcoding into React components, saving to headless databases, or creating custom template libraries.
FileKit Export Pathways (.sketch File vs. Template JSON)
Loading diagram canvas...
Pan & zoom enabled • 1-click PNG exportPowered by @filekit-studio/diagram

2. Step 1: Exporting Template JSON from Sketch

  1. In the Sketch Whiteboard, select the elements you want to export (or select nothing to export all elements).
  2. Click Export & Save in the top bar (or press Ctrl+Shift+E).
  3. Switch to the .sketch tab.
  4. Under Template Format, click Copy Template JSON.
  5. The normalized JSON is now copied to your clipboard, ready to paste directly into your codebase.

3. Step 2: Displaying a Clean Vector Diagram with <SketchViewer />

The simplest way to use exported diagram JSON in code is with <SketchViewer />. It renders an interactive, vector-sharp diagram with zero UI chrome (no toolbars, no sidebars), ideal for documentation, blog posts, and analytics dashboards.

Live Interactive Showcase

Inspect the live 3-tier architecture diagram below. You can pan, zoom, and inspect elements:

3-Tier Cloud Architecture (Rendered with SketchViewer)
Loading whiteboard canvas...
Pan & zoom enabled • 1-click PNG exportPowered by @filekit-studio/sketch

Complete Code Implementation

Here is how you render this exact diagram in your React or Next.js application:

components/cloud-architecture-diagram.tsx
"use client";

import React from "react";
import dynamic from "next/dynamic";
import type { SketchBoardElement } from "@filekit-studio/sketch";
import "@filekit-studio/sketch/styles.css";

// Dynamic import with ssr: false for Next.js App Router
const SketchViewer = dynamic(
  () => import("@filekit-studio/sketch").then((mod) => mod.SketchViewer),
  { ssr: false }
);

// 1. Paste your exported template elements here
const CLOUD_ARCHITECTURE_ELEMENTS: SketchBoardElement[] = [
  {
    id: "client",
    type: "rectangle",
    x: 40,
    y: 110,
    width: 170,
    height: 100,
    strokeColor: "#0284c7",
    strokeWidth: 2,
    strokeStyle: "solid",
    fillColor: "#e0f2fe",
    fillStyle: "hachure",
    text: "Web Client\n(Next.js App)",
    textColor: "#0369a1",
    fontSize: 13,
    fontFamily: "sans",
    textAlign: "center",
    edgeStyle: "round",
  },
  {
    id: "gateway",
    type: "diamond",
    x: 290,
    y: 100,
    width: 160,
    height: 120,
    strokeColor: "#4f46e5",
    strokeWidth: 2,
    strokeStyle: "solid",
    fillColor: "#e0e7ff",
    fillStyle: "hachure",
    text: "API Gateway\n(Auth & Routing)",
    textColor: "#3730a3",
    fontSize: 12,
    fontFamily: "sans",
    textAlign: "center",
  },
  {
    id: "database",
    type: "cylinder",
    x: 530,
    y: 95,
    width: 170,
    height: 130,
    strokeColor: "#059669",
    strokeWidth: 2,
    strokeStyle: "solid",
    fillColor: "#d1fae5",
    fillStyle: "hachure",
    text: "Database Cluster\n(PostgreSQL)",
    textColor: "#065f46",
    fontSize: 13,
    fontFamily: "sans",
    textAlign: "center",
  },
  {
    id: "conn-1",
    type: "arrow",
    x: 210,
    y: 160,
    width: 80,
    height: 0,
    arrowType: "straight",
    strokeColor: "#0284c7",
    strokeWidth: 2,
    strokeStyle: "solid",
    fillColor: "transparent",
    fillStyle: "solid",
    endArrowhead: "arrow",
  },
  {
    id: "conn-2",
    type: "arrow",
    x: 450,
    y: 160,
    width: 80,
    height: 0,
    arrowType: "straight",
    strokeColor: "#4f46e5",
    strokeWidth: 2,
    strokeStyle: "solid",
    fillColor: "transparent",
    fillStyle: "solid",
    endArrowhead: "arrow",
  },
];

export function CloudArchitectureDiagram() {
  return (
    <div className="w-full h-[360px] rounded-2xl border border-neutral-200 dark:border-neutral-800 overflow-hidden bg-white dark:bg-[#15161a]">
      <SketchViewer
        elements={CLOUD_ARCHITECTURE_ELEMENTS}
        autoFit={true}              // Scales diagram to fit container perfectly
        showZoomControls={true}     // Floating zoom in / out / reset pill
        gridStyle="dots"            // "grid" | "dots" | "cross" | "none"
      />
    </div>
  );
}

4. Step 3: Loading a Pre-Configured Template into <SketchEditor />

If you want users to open the full interactive whiteboard studio pre-populated with an architecture starter template that they can edit, resize, and draw on, pass your template to defaultValue:

Live Interactive Showcase

Try editing this starter template right in the canvas below:

Interactive Event-Driven Pipeline Starter Template
Loading whiteboard canvas...
Pan & zoom enabled • 1-click PNG exportPowered by @filekit-studio/sketch

Complete Code Implementation

app/editor/page.tsx
"use client";

import React from "react";
import dynamic from "next/dynamic";
import type { SketchBoardElement } from "@filekit-studio/sketch";
import "@filekit-studio/sketch/styles.css";

const SketchEditor = dynamic(
  () => import("@filekit-studio/sketch").then((mod) => mod.SketchEditor),
  { ssr: false }
);

const EVENT_PIPELINE_STARTER: SketchBoardElement[] = [
  {
    id: "source",
    type: "capsule",
    x: 60,
    y: 120,
    width: 160,
    height: 80,
    strokeColor: "#0284c7",
    strokeWidth: 2,
    strokeStyle: "solid",
    fillColor: "#e0f2fe",
    fillStyle: "solid",
    text: "Event Producer",
    textColor: "#0369a1",
    fontSize: 14,
    fontFamily: "sans",
    textAlign: "center",
  },
  {
    id: "queue",
    type: "rectangle",
    x: 300,
    y: 110,
    width: 180,
    height: 100,
    strokeColor: "#ea580c",
    strokeWidth: 2,
    strokeStyle: "solid",
    fillColor: "#ffedd5",
    fillStyle: "hachure",
    text: "Kafka Topic\n(Partitioned Log)",
    textColor: "#9a3412",
    fontSize: 13,
    fontFamily: "sans",
    textAlign: "center",
  },
  {
    id: "consumer",
    type: "capsule",
    x: 560,
    y: 120,
    width: 160,
    height: 80,
    strokeColor: "#16a34a",
    strokeWidth: 2,
    strokeStyle: "solid",
    fillColor: "#dcfce7",
    fillStyle: "solid",
    text: "Stream Worker",
    textColor: "#15803d",
    fontSize: 14,
    fontFamily: "sans",
    textAlign: "center",
  },
  {
    id: "arr-1",
    type: "arrow",
    x: 220,
    y: 160,
    width: 80,
    height: 0,
    arrowType: "straight",
    strokeColor: "#0284c7",
    strokeWidth: 2,
    strokeStyle: "solid",
    fillColor: "transparent",
    fillStyle: "solid",
    endArrowhead: "arrow",
  },
  {
    id: "arr-2",
    type: "arrow",
    x: 480,
    y: 160,
    width: 80,
    height: 0,
    arrowType: "straight",
    strokeColor: "#ea580c",
    strokeWidth: 2,
    strokeStyle: "solid",
    fillColor: "transparent",
    fillStyle: "solid",
    endArrowhead: "arrow",
  },
];

export default function WhiteboardStudioPage() {
  return (
    <div className="w-screen h-screen overflow-hidden">
      <SketchEditor
        boardName="Event-Driven Architecture"
        defaultValue={EVENT_PIPELINE_STARTER}
        storageKey="my_event_pipeline_v1"
        toastPosition="top-right"
        gridStyle="grid"
      />
    </div>
  );
}

5. Step 4: Registering Custom Templates in <SketchEditor />

You can customize the architecture blueprints shown in the Templates flyout menu using the templates prop.

FileKit supports both static .json files and TypeScript .ts generator functions. Both are passed into the exact same elements field of a TemplateDefinition object.

TemplateDefinition Architecture (.json vs .ts)
Loading diagram canvas...
Pan & zoom enabled • 1-click PNG exportPowered by @filekit-studio/diagram

5.1 Approach A: Using a Static .json File

Use this when you have pre-drawn diagrams exported from Sketch or fetched from an API database.

  1. Draw your diagram in the Sketch canvas and export it as Template JSON.
  2. Save the JSON file into your project (e.g. templates/auth-pipeline.json):
templates/auth-pipeline.json
[
  {
    "id": "node_client",
    "type": "rectangle",
    "x": -140,
    "y": -30,
    "width": 130,
    "height": 60,
    "text": "Client App",
    "strokeColor": "#3b82f6",
    "strokeWidth": 2,
    "strokeStyle": "solid",
    "fillColor": "#e0f2fe",
    "fillStyle": "solid",
    "opacity": 1,
    "zIndex": 1
  },
  {
    "id": "node_api",
    "type": "rectangle",
    "x": 80,
    "y": -30,
    "width": 130,
    "height": 60,
    "text": "API Gateway",
    "strokeColor": "#10b981",
    "strokeWidth": 2,
    "strokeStyle": "solid",
    "fillColor": "#dcfce7",
    "fillStyle": "solid",
    "opacity": 1,
    "zIndex": 2
  },
  {
    "id": "arrow_conn",
    "type": "arrow",
    "x": -10,
    "y": 0,
    "width": 90,
    "height": 0,
    "strokeColor": "#38bdf8",
    "strokeWidth": 2,
    "startBinding": { "elementId": "node_client", "anchor": "right" },
    "endBinding": { "elementId": "node_api", "anchor": "left" }
  }
]
  1. In your React or Next.js component, import the JSON file and pass it to elements:
app/templates-demo/json-template.tsx
"use client";

import React from "react";
import dynamic from "next/dynamic";
import type { TemplateDefinition, SketchBoardElement } from "@filekit-studio/sketch";
import authPipelineJson from "./templates/auth-pipeline.json";
import "@filekit-studio/sketch/styles.css";

const SketchEditor = dynamic(
  () => import("@filekit-studio/sketch").then((mod) => mod.SketchEditor),
  { ssr: false }
);

const CUSTOM_JSON_TEMPLATES: TemplateDefinition[] = [
  {
    id: "auth_pipeline",
    title: "Auth & API Pipeline",
    category: "Security",
    description: "Standard OAuth2 client and API gateway structure",
    tag: "Security",
    tagColor: "bg-emerald-100 dark:bg-emerald-950/60 text-emerald-700 dark:text-emerald-300 border-emerald-200 dark:border-emerald-800",
    // ----------------------------------------------------
    // Passed directly as a static JSON array:
    // ----------------------------------------------------
    elements: authPipelineJson as SketchBoardElement[],
  },
];

export function JsonTemplatesEditor() {
  return (
    <div className="w-screen h-screen overflow-hidden">
      <SketchEditor
        boardName="JSON Templates Studio"
        templates={CUSTOM_JSON_TEMPLATES}
      />
    </div>
  );
}

[!NOTE] Automatic Collision-Free IDs & Centering: When a user selects a JSON template, FileKit's engine automatically centers the elements around the user's current camera viewport and regenerates new element IDs while updating arrow bindings (startBinding & endBinding), so inserting the template multiple times never causes ID collisions.


5.2 Approach B: Using a TypeScript Generator (.ts)

Use a .ts file when you want dynamic theme adaptation (light mode vs. dark mode colors) or calculated coordinate math:

templates/dynamic-k8s-template.ts
import type { TemplateDefinition, SketchBoardElement } from "@filekit-studio/sketch";

export const dynamicK8sTemplate: TemplateDefinition = {
  id: "dynamic_k8s_node",
  title: "Dynamic K8s Worker Node",
  category: "Engineering",
  description: "Theme-adaptive Kubernetes pod and container layout",
  tag: "Kubernetes",
  tagColor: "bg-blue-100 dark:bg-blue-950/60 text-blue-700 dark:text-blue-300 border-blue-200 dark:border-blue-800",
  // ----------------------------------------------------
  // Dynamic generator function receives (centerPt, isDark):
  // ----------------------------------------------------
  elements: (centerPt, isDark) => {
    // Dynamic palette switching based on the current canvas theme
    const containerBg = isDark ? "#141824" : "#f8fafc";
    const containerStroke = isDark ? "#38bdf8" : "#0284c7";
    const podBg = isDark ? "#1e293b" : "#ffffff";
    const textColor = isDark ? "#f8fafc" : "#0f172a";

    return [
      {
        id: "k8s_node",
        type: "rectangle",
        x: centerPt.x - 160,
        y: centerPt.y - 100,
        width: 320,
        height: 200,
        strokeColor: containerStroke,
        strokeWidth: 2,
        strokeStyle: "dashed",
        fillColor: containerBg,
        fillStyle: "solid",
        edgeStyle: "round",
        text: "K8s Worker Node (Zone A)",
        textColor: textColor,
        fontSize: 14,
        zIndex: 1,
      },
      {
        id: "pod_1",
        type: "rectangle",
        x: centerPt.x - 130,
        y: centerPt.y - 40,
        width: 120,
        height: 110,
        strokeColor: isDark ? "#34d399" : "#059669",
        strokeWidth: 2,
        fillColor: podBg,
        fillStyle: "solid",
        edgeStyle: "round",
        text: "Pod: Ingress",
        textColor: textColor,
        fontSize: 12,
        zIndex: 2,
      },
      {
        id: "pod_2",
        type: "rectangle",
        x: centerPt.x + 10,
        y: centerPt.y - 40,
        width: 120,
        height: 110,
        strokeColor: isDark ? "#a78bfa" : "#7c3aed",
        strokeWidth: 2,
        fillColor: podBg,
        fillStyle: "solid",
        edgeStyle: "round",
        text: "Pod: Service",
        textColor: textColor,
        fontSize: 12,
        zIndex: 3,
      },
    ] as SketchBoardElement[];
  },
};

5.3 Database Schema & ERD Template (tableStyle: 'database')

You can also package complete relational database schemas and live entity-relationship diagrams as custom blueprints:

templates/erd-schema-template.ts
import type { TemplateDefinition, SketchBoardElement } from "@filekit-studio/sketch";

export const erdSchemaTemplate: TemplateDefinition = {
  id: "erd_ecommerce",
  title: "E-Commerce Database Schema",
  category: "Databases",
  description: "Relational entity schema for users, orders, and animated foreign key flows",
  tag: "SQL & ERD",
  tagColor: "bg-emerald-100 dark:bg-emerald-950/60 text-emerald-700 dark:text-emerald-300 border-emerald-200 dark:border-emerald-800",
  elements: (centerPt, isDark) => {
    const primaryBorder = isDark ? "#38bdf8" : "#0284c7";
    const primaryFill = isDark ? "#0f172a" : "#f0f9ff";

    return [
      // 1. Users Table Entity
      {
        id: "tbl_users",
        type: "table",
        tableStyle: "database",
        x: centerPt.x - 260,
        y: centerPt.y - 80,
        width: 220,
        height: 160,
        strokeColor: primaryBorder,
        strokeWidth: 2,
        strokeStyle: "solid",
        fillColor: primaryFill,
        fillStyle: "solid",
        opacity: 1,
        zIndex: 1,
        rows: 4,
        cols: 2,
        colWidths: [120, 100],
        rowHeights: [36, 32, 32, 32],
        hasHeaderRow: true,
        cells: {
          "0,0": { text: "users", bold: true, align: "left" },
          "1,0": { text: "id", align: "left" },
          "1,1": { text: "uuid", align: "right" },
          "2,0": { text: "name", align: "left" },
          "2,1": { text: "varchar(100)", align: "right" },
          "3,0": { text: "email", align: "left" },
          "3,1": { text: "varchar(255)", align: "right" },
        },
      },
      // 2. Orders Table Entity
      {
        id: "tbl_orders",
        type: "table",
        tableStyle: "database",
        x: centerPt.x + 80,
        y: centerPt.y - 80,
        width: 240,
        height: 192,
        strokeColor: primaryBorder,
        strokeWidth: 2,
        strokeStyle: "solid",
        fillColor: primaryFill,
        fillStyle: "solid",
        opacity: 1,
        zIndex: 1,
        rows: 5,
        cols: 2,
        colWidths: [130, 110],
        rowHeights: [36, 32, 32, 32, 32],
        hasHeaderRow: true,
        cells: {
          "0,0": { text: "orders", bold: true, align: "left" },
          "1,0": { text: "id", align: "left" },
          "1,1": { text: "uuid", align: "right" },
          "2,0": { text: "user_id", align: "left" },
          "2,1": { text: "uuid (FK)", align: "right" },
          "3,0": { text: "total", align: "left" },
          "3,1": { text: "numeric(10,2)", align: "right" },
          "4,0": { text: "status", align: "left" },
          "4,1": { text: "varchar(32)", align: "right" },
        },
      },
      // 3. Foreign Key Relationship Connector with Animated Data Pulse
      {
        id: "fk_user_orders",
        type: "arrow",
        arrowType: "elbow",
        x: centerPt.x - 40,
        y: centerPt.y - 30,
        width: 120,
        height: 0,
        strokeColor: primaryBorder,
        strokeWidth: 2,
        strokeStyle: "solid",
        fillColor: "transparent",
        fillStyle: "solid",
        opacity: 1,
        zIndex: 2,
        endArrowhead: "arrow",
        flowAnimation: "packet-pulse",
        flowSpeed: "normal",
        flowTrigger: "continuous",
      },
    ] as SketchBoardElement[];
  },
};

5.4 Keeping Built-in Templates Alongside Custom Ones

When you provide the templates prop, it replaces the default templates. If you want to keep all 14 built-in system architectures and simply append your custom templates, import DIAGRAM_TEMPLATES and spread it:

app/editor/page.tsx
import { SketchEditor, DIAGRAM_TEMPLATES } from "@filekit-studio/sketch";
import { dynamicK8sTemplate } from "./templates/dynamic-k8s-template";
import { erdSchemaTemplate } from "./templates/erd-schema-template";

export default function WhiteboardPage() {
  return (
    <SketchEditor
      // Custom templates show up first, followed by all 14 built-in blueprints!
      templates={[erdSchemaTemplate, dynamicK8sTemplate, ...DIAGRAM_TEMPLATES]}
    />
  );
}

5.5 How to Hide or Disable the Templates Feature Completely

If your application only needs a blank drawing canvas and you don't want users inserting templates at all, set showTemplates: false in uiConfig:

TypeScript (TSX)
<SketchEditor
  uiConfig={{
    // ----------------------------------------------------
    // Disables the flyout and hides template wand button:
    // ----------------------------------------------------
    showTemplates: false,
  }}
/>

5.6 Auto-Converting Canvas Drawings with createTemplateFromElements

You can also let your users draw diagrams on the canvas, convert their drawings into normalized templates programmatically, and save them to your database:

TypeScript
import { createTemplateFromElements, type SketchBoardElement } from "@filekit-studio/sketch";

// Elements drawn on the canvas:
const userElements: SketchBoardElement[] = [ /* ... */ ];

// Normalizes coordinates around (0, 0) and generates metadata:
const customTemplate = createTemplateFromElements(userElements, {
  title: "My Team Architecture",
  category: "Engineering",
  description: "User-saved pipeline template",
});

// Now save customTemplate as JSON to PostgreSQL, Supabase, or localStorage!

6. Summary Comparison

ObjectiveRecommended ComponentTypical Use Case
Display a read-only diagram<SketchViewer elements={...} />Documentation, blog posts, static architecture showcases, and embed cards.
Open an editable starter canvas<SketchEditor defaultValue={...} />Starting a whiteboard pre-populated with an architecture for user editing.
Add blueprints to Templates menu<SketchEditor templates={[...]} />Registering custom company architecture templates into the left tool flyout.
Preserve complete whiteboard stateExport as .sketch fileFull board backups to disk, version control, or cloud storage.

On this page