Developers/Graphics JS/Course and graphics

Core guide 02

Choose a course. Define a graphic.

A graphic request identifies measured course data, selects a hole, green, complete course, or side-view elevation profile, and defines the clean artifact that every authorized overlay must match.

Courses

Start with a stable CADDIE.100 course ID.

listCourses returns the licensed course directory available to the current publishable key. Use the stable course ID in every subsequent request instead of relying on a display name.

const courses = await caddie.listCourses();

const raymondMemorial = courses.find(
  (course) => course.name === "Raymond Memorial",
);

Pass an AbortSignal through the optional operation options when course search belongs to a component that may unmount or issue a newer request.

Browser reuse

Reuse verified pixels without weakening overlay authorization.

Publishable-key clients cache immutable image Blobs in IndexedDB for two hours by default. Graphics JS partitions entries with a one-way representation of the key, verifies the artifact SHA-256 on write and read, removes expired or corrupt entries, and bounds storage by age, count, bytes, and least-recently-used access.

The render descriptor and overlay receipt stay in the current tab only and never outlive the server's 30-minute authorization. A same-tab reload can therefore avoid both requests. A new tab or expired receipt makes one descriptor request, then reuses the larger image only when the refreshed artifact key, checksum, dimensions, and content type still match. If they differ, the SDK downloads the replacement before requesting components.

const caddie = createCaddie100Client({
  apiKey: "c100_pk_live_…",
  imageCache: {
    maxAgeMs: 2 * 60 * 60 * 1000,
    maxEntries: 24,
    maxBytes: 100 * 1024 * 1024,
  },
});

// Clear only Graphics JS entries for this API origin.
await caddie.clearImageCache();

// Opt out when the host application requires it.
const uncached = createCaddie100Client({
  apiKey: "c100_pk_live_…",
  imageCache: false,
});
Image bytes onlyThe persistent cache excludes raw API keys, render receipts, overlays, placement instructions, sidecars, coordinates, measurements, and putting data. Storage restrictions or quota failures become ordinary cache misses and never prevent rendering.

Inspect asset.descriptorCacheState and asset.imageCacheState for HIT/MISS diagnostics. Mounted views expose the same values on view.root as data-caddie-descriptor-cache and data-caddie-image-cache.

GraphicRequest

Describe the clean rendered artifact.

const graphicRequest = {
  courseId: "34697689-6423-4c2e-a2c4-b0ecbbfc77d2",
  subject: { type: "hole", holeNumber: 1 },
  output: {
    format: "webp",
    width: 900,
    height: 1500,
    quality: 92,
  },
  style: {
    graphicStyle: "traditional",
    paperTheme: "light",
    fairwayPattern: "auto",
    teePattern: "plain",
    perimeterTreatment: "classic",
    nearbyHoles: "hidden",
  },
  composition: {
    layout: "portrait",
    flagAnchor: "middle",
    teeAnchor: "middle",
    padding: [0.025, 0.05],
  },
};
GroupPurposeCommon values
courseIdStable measured-course identity.UUID from listCourses
subjectSelects the spatial subject to compose.hole, green, course, or profile-elevation
outputDefines encoding, dimensions, and quality.WebP, PNG, JPEG/JPG
styleSelects the graphic style and controls its paper, terrain, turf, context, perimeter, or elevation-profile presentation.traditional, plus explicit renderer settings
style.pencilFeaturesControls Pencil paths, buildings, and the final envelope outline.buildings/paths default false; perimeter defaults true
style.graphicStylingDeep-merges the supported Pencil or Colored Pencil palette into versioned defaults.Pencil paper/strokes with optional feature fills and green-boundary width; Colored Pencil ground/features; plus elevation-profile colors
compositionFits and orients a hole inside the requested aspect ratio.Portrait/landscape, anchors, and CSS-style padding
courseCompositionControls spacing around the automatically rotated full course.auto or CSS-style padding
greenCompositionControls a green-detail crop, orientation, and placement.Approach/north, bottom-default approach edge with explicit alternatives or auto compatibility, mutually exclusive output-space or meter padding, rotation, center/auto/edge/corner gravity
greenDataAdds supported green-detail analysis to the clean image.Green elevation heatmap and break presentation
One exact artifactWidth and height define both the output resolution and composition aspect ratio. The overlay service validates its placements against this render ID, request signature, artifact checksum, and canvas before returning any display pixels.

Pencil-family styling

Build a custom graphic language from stable style defaults.

Pencil and Colored Pencil accept their own style.graphicStyling schema for hole, green, course, and profile-elevation subjects. The API retains only supported keys, validates #RRGGBB and #RRGGBBAA colors plus supported stroke widths from 0 through 16, then strictly deep-merges the partial object into that style's versioned defaults.

Pencil exposes light/dark paper, graphite strokes, opt-in fills for fairway, tee, green, bunker, water, tree, and forest features, plus a configurable green-boundary width; those feature fills default to transparent. Colored Pencil exposes ground visibility, shared strokes, and colors for green, fairway, tee, bunker, water, tree, forest, path, parking, and building features. Both expose light/dark elevation-profile palettes; the profile background chooses the applicable palette. Every normalized result participates in render and cache identity. Unknown properties, malformed values, cross-style fields, and use with Traditional are rejected rather than ignored.

const customPencilProfile = await caddie.renderGraphic({
  courseId: "34697689-6423-4c2e-a2c4-b0ecbbfc77d2",
  subject: { type: "profile-elevation", holeNumber: 2 },
  style: {
    graphicStyle: "pencil",
    graphicStyling: {
      paper: { light: "#FFFDF7" },
      strokes: { light: { primary: "#202124CC" } },
      profileElevation: {
        light: { surface: "#4D514D", labelStroke: "#4D514D55" },
      },
    },
  },
});
const customColoredPencil = await caddie.renderGraphic({
  courseId: "34697689-6423-4c2e-a2c4-b0ecbbfc77d2",
  subject: { type: "green", holeNumber: 2 },
  style: {
    graphicStyle: "colored-pencil",
    graphicStyling: {
      ground: { visible: false },
      strokes: { primary: "#24452ECC" },
      features: {
        green: {
          fill: "#B7D99A",
          strokeColor: "#24452ECC",
          strokeWidth: 2,
        },
      },
    },
  },
});

Pencil optional features

Add secondary context without changing Pencil's hierarchy.

The Pencil branch of GraphicRequest accepts style.pencilFeatures.buildings, style.pencilFeatures.paths, and style.pencilFeatures.perimeter for hole, green, and course subjects. Buildings and paths default false; perimeter defaults true. Buildings use simple Overture footprints. Paths combine course-authored cart paths with the restrained Overture service and non-motorized allowlist.

Paths and buildings remain visually subordinate and clipped to the envelope selected by perimeterTreatment. Setting perimeter to false skips only the final Pencil outline stroke, retaining the same envelope, projection, clipping, and framing. The options are absent from the Traditional and Colored Pencil type branches and are not valid for profile-elevation. Each pixel-distinct combination has its own normalized render identity and cache entry.

import type { GraphicRequest } from "@caddie100/graphics-js";

// Omitted options preserve today's Pencil output; both default false.
const defaultPencilRequest: GraphicRequest = {
  courseId: "34697689-6423-4c2e-a2c4-b0ecbbfc77d2",
  subject: { type: "hole", holeNumber: 1 },
  output: { format: "webp", width: 1440, height: 2400 },
  style: { graphicStyle: "pencil" },
};

const contextualPencilRequest: GraphicRequest = {
  ...defaultPencilRequest,
  style: {
    graphicStyle: "pencil",
    pencilFeatures: { buildings: true, paths: true, perimeter: false },
  },
};
API capability availableThe current API accepts either option. False or omitted values remain backward-compatible. The Graphics JS package source includes the request shape, while its next npm publication remains a separate release step.

Elevation profiles

Render a hole as a measured side view.

profile-elevation is a hole-scoped subject with a 1600 × 600 default output. Its style controls select smooth or stepped terrain, label and yardage sizes, an optional single tee by id, name, or color, tee-marker size, yards/feet/meters for horizontal stations, CSS-style outer padding, and a six-digit RGB background. Signed vertical elevation remains in feet. Every tee position renders as a colored square by default; an unmatched single-tee selector falls back to the furthest tee. Labeled approach stations use outlined circles. At the default size tee and approach markers measure 18 and 14 pixels respectively, with outlines chosen to remain legible when printed.

const profileRequest = {
  courseId: "34697689-6423-4c2e-a2c4-b0ecbbfc77d2",
  subject: { type: "profile-elevation", holeNumber: 7 },
  output: { format: "png", width: 1600, height: 600 },
  style: {
    graphicStyle: "colored-pencil",
    profileLineStyle: "stepped",
    profileLabelSize: "medium",
    profileYardageSize: 12,
    profileTee: "Green",
    profileTeeMarkerSize: 36,
    profileDistanceUnit: "meters",
    profilePadding: [0, 24, 16, 24],
    profileBackgroundColor: "#FFFFFF",
  },
};

const profile = await caddie.renderGraphic(profileRequest);
profile.download("hole-7-elevation-profile.png");
profile.destroy();
Clean artifact onlyElevation-profile render descriptors intentionally authorize no Smart Components. Use renderGraphic for a downloadable asset, or call mount with an empty component list for a responsive browser view. The renderer reserves enough top space for the flag and elevation pills, even at the highest terrain station. Hole, course, and green composition or analysis fields do not apply to profiles.

Inspect profileElevation.presentation in renderer metadata for the resolved marker styles and dimensions, top safety band, minimum label-to-surface gap, padding, background, and omitted-distance break. Marker fields include teeMarkerStyle, teeMarkerSizePixels, approachMarkerStyle, approachMarkerDiameterPixels, and markerOutlinePixels.

Delivery methods

Choose the level of browser behavior you need.

// Descriptor only: create the render and receive its artifact contract.
const descriptor = await caddie.createGraphic(graphicRequest);

// Browser asset: authenticate the artifact and create a temporary blob URL.
const asset = await caddie.renderGraphic(graphicRequest);
asset.download("raymond-hole-1.webp");
asset.destroy();

// Interactive view: mount the image and manage optional HTML components.
// The default contain stage preserves the complete artifact in fixed-size hosts.
const view = await caddie.mount(container, graphicRequest, overlays, { fit: "contain" });
createGraphic

Descriptor

Returns the clean image contract and short-lived render receipt without downloading the artifact.

renderGraphic

Asset

Downloads the authenticated image and exposes a blob-backed URL plus download and cleanup methods.

mount

Interactive view

Creates an observed, aspect-ratio-locked stage containing the image and its independently requested overlay layer.

setSmartComponents / addSmartComponent

Components later

Reconciles or appends independently identified instances, including repeated component types, while reusing view-cached placements.

Lifecycle

Cancel stale work and release browser assets.

  • Pass an AbortSignal to listCourses, createGraphic, renderGraphic, or mount when the calling UI can be replaced.
  • Use the default contain fit for fixed cards and split panes. Use width when the host grows or scrolls vertically.
  • Call asset.destroy() for a standalone rendered asset after its blob URL is no longer needed.
  • Call view.destroy() when an interactive graphic unmounts. It disconnects responsive observation, aborts active overlay work, removes image handlers and DOM, and revokes the asset URL.