CXTF
Coordinates Exchange Text-Format
A plain-text format for hierarchical 2D and 3D vector graphics and map data: human-readable, explicitly structured, and built for seamless exchange between applications. One command per line, no hidden state, no surprises.
About CXTF
Coordinates Exchange Text-Format (CXTF) is a line-based text format for exchanging hierarchical 2D or 3D geometric data for vector maps and any other graphics with styling information. It provides a human-readable way to represent vector graphics including paths, shapes, colours, gradients, and hierarchical organisation. The format was developed by Stefan Gies from 1992 onwards, evolving from an earlier binary precursor (CH5) into its current human-readable form.
Designed for
Interoperability between vector graphics applications — easy parsing and generation — preservation of visual styling (colours, gradients, strokes, fills) — hierarchical document structure (layers, groups).
Syntax
CXTF uses a line-oriented, space-delimited syntax. Each line contains exactly one command followed by its parameters. Comments begin with ~ and the rest of that line is ignored.
Commands are typically 1–2 characters long and case-sensitive (with a few case-insensitive exceptions). Parameters are separated by spaces: numbers (integers or floats) for coordinates and values, strings for names and text, and colours in BGR(A) format.
A backslash \ at the end of a line is a continuation marker — the next line is appended to the current one without inserting a line break. The pipe character | is an explicit line separator equivalent to a newline, allowing multiple commands on the same physical line.
Strings (titles, layer names, group names) must encode special characters using $XX hex escaping: $ | = ; ~ \ / # @ & " CR LF. Because | acts as a line separator, it must be encoded as $7C inside string values.
Colours
Colours are specified in BGRA order (Blue Green Red Alpha, 0–255). The alpha channel is optional and defaults to 255 (fully opaque). The alternative commands -c and -f accept colours in RGBA order — these exist so third-party exporters that work natively in RGB do not need to swap channels before writing CXTF.
Dimensionality
The dimensionality of coordinate vectors is set once in the file header with the $ command:
Parameters typed DimVector in the command reference change their value count with dimensionality — 2 values in 2D, 3 values in 3D. These are exclusively the geometry coordinate commands (p, s, l, L, z, Z, H, M and related). Parameters typed Vector are always a fixed 2-value pair regardless of $ — this applies to transformation commands (O, S, U) and structural commands (<, >).
The Bézier commands z/Z have two DimVector anchor points before the endpoint. In 3D each gains a Z component, shifting the position of all subsequent parameters — unlike every other command where vectors are at the end.
Since format version 6.3, the Z component of a DimVector is optional in 3D files. The Z value persists within a group: the polygon or polyline start point (p or s) establishes the initial Z, and all subsequent points (l, z, Z etc.) inherit it until a new explicit Z value appears. Z is reset at each new group. This makes contour-line data significantly more compact — the elevation only needs to be stated once per contour line.
File Extensions
CXTF content is typically stored in one of two forms. A plain .cxtf file contains only the vector data; any referenced images, textures, symbols and fonts must reside alongside it on the file system or server. A .cxzip archive bundles the .cxtf file together with all its resources into a single standard ZIP file. The main CXTF file inside the archive is always named __main.cxtf; the original filename is recorded within it via the ofn command.
Image Resources
Images, textures and symbols referenced in a CXTF file are identified by their basename only — the directory path is stripped at parse time. All image basenames within a project must therefore be unique regardless of extension: having both photo.jpg and photo.png in the same project is not permitted.
The GGG command (formerly GG) applies colour filtering to an image. To avoid recalculating the filter every time the file is opened, the adjusted result is written alongside the source as a PNG with a suffixed second extension: photo.jpg becomes Adjusted/photo.jpg.png. When this pre-computed file is present — either on disk or inside a .cxzip archive — it is loaded directly in preference to the original, making large projects with many filtered images open instantly.
Style Model
Of all CXTF commands, only c (stroke colour) and f (fill colour) are stateful — their values persist across subsequent elements until explicitly changed. Since version 6.3, the Z coordinate of DimVector parameters in 3D files follows the same principle: once set by the element start point (p or s), it is carried forward within the group until a new explicit Z value appears. Every other property command (cp, w, t, fg, fh, n, U, O, R, S, zr and so on) is a modifier applied to the immediately preceding element, group, folder, image or symbol. This keeps the format explicit and predictable: no style inheritance cascades through the hierarchy.
Design Philosophy
- Text-based — human-readable and editable in any text editor
- Explicit — every style and coordinate is stated directly
- Sequential — commands are processed in order
- Hierarchical — Project → Folders → Groups → Elements, with a separate Image Overlay hierarchy
- Stateful — stroke colour (
c) and fill colour (f) persist across elements until changed; all other modifiers apply to the immediately preceding element - Extensible — new commands can be added while maintaining backward compatibility
Typical File Structure
Browse the Documentation
Embedding Guide
Quickstart
Include the renderer script and place a <cxtf-view> tag anywhere in your HTML. No build step, no dependencies.
<!-- 1. Load the renderer (once, anywhere in the page) --> <script src="docs/cxtf-renderer.js" defer></script> <!-- 2. Place the viewer --> <cxtf-view src="mymap.cxtf" width="600" height="400"></cxtf-view>
That is all that is required. The component renders inside a Shadow DOM canvas and fires a cxtf-ready event when loaded.
defer attribute on the script tag ensures the custom element is defined before any <cxtf-view> tags in the document are connected.Inline vs src
There are two ways to supply CXTF content to the component. Use one or the other — not both on the same element.
src attribute — load from file
Fetches a .cxtf or .cxzip file from the server. The path is relative to the page URL. A CORS header (Access-Control-Allow-Origin) is required if loading cross-origin.
When a .cxzip archive is loaded, the component unpacks it in the browser using the built-in DecompressionStream API (no external libraries required), reads __main.cxtf as the main file, and resolves all resource references (images, textures, symbols, fonts) directly from the archive as blob URLs.
<cxtf-view src="examples/mymap.cxtf" width="800" height="500" centered="true"></cxtf-view>
Inline content — embed CXTF directly
Place CXTF text as the text content of the element. Suitable for small, self-contained examples or when serving static HTML without separate asset files.
<cxtf-view width="400" height="300"> CXTF ? Inline example $ 2 b 30 30 30 * Box c 100 160 80 f 60 100 50 180 p 0 0 l 20 0 l 20 15 l 0 15 L 0 0 </cxtf-view>
src and inline text content on the same element. If src is present it takes precedence and the text content is ignored.Attributes
All attributes except src, width, and height are boolean and take the literal string values "true" or "false".
| Attribute | Type | Default | Description |
|---|---|---|---|
| src | string | — | URL of the .cxtf file to load. Omit to use inline text content instead. |
| width | integer | 600 | Initial canvas width in CSS pixels. The canvas scales with devicePixelRatio for sharp rendering on HiDPI displays. |
| height | integer | 400 | Initial canvas height in CSS pixels. |
| centered | boolean | false | When true, the viewport is centred on the focus point. When false, the origin is the top-left corner. |
| interactive | boolean | false | Enables mouse-wheel zoom and right-click (or touch) pan. Disable for static embeds. |
| transparent | boolean | true | When true (default), the checkered transparency background is suppressed and the CXTF background colour is drawn at its own alpha. Set "false" to show a checkerboard for transparent areas. |
| xray | boolean | false | Outline-only (X-ray) render mode. All fills are suppressed; only stroke outlines are drawn. |
| cross | boolean | false | Draws a crosshair at the focus point. Useful for debugging centred viewports. |
| nodes | boolean | false | When true, folders and groups that are invisible by default (# marker in CXTF) are shown in the tree panel. Does not affect canvas rendering. |
All attributes with their default values:
<cxtf-view src="" <!-- omit for inline content --> width="600" height="400" centered="false" interactive="false" transparent="true" xray="false" cross="false" nodes="false"></cxtf-view>
Packaging as .cxzip
A .cxzip file is a standard ZIP archive (DEFLATE compression, no Zip64) containing a CXTF project and all its resources in one portable file. The component loads it identically to a plain .cxtf — just point the src attribute at the archive.
<cxtf-view src="maps/myproject.cxzip" width="800" height="500" centered="true"></cxtf-view>
Archive structure
| Path | Description |
|---|---|
| __main.cxtf | The main CXTF file. Always this exact name. The original filename is recorded inside it via the ofn command. |
| foo.jpg bar.png … |
Image resources in the archive root. All image basenames must be unique regardless of extension — photo.jpg and photo.png in the same archive is not permitted. |
| Adjusted/foo.jpg.png | Pre-adjusted version of foo.jpg produced by the GGG (formerly GG) colour-filtering command. When present, this takes priority over the root entry so the adjusted image is used directly without recalculating the filter at load time. |
| font.ttf … | Font resources, always in the archive root (no subdirectory). |
Resource resolution order
For each image reference the component checks in this order:
- Is there an
Adjusted/entry whose name matches (e.g.Adjusted/foo.jpg.pngfor a reference tofoo.jpg)? → use that blob URL. - Otherwise use the root entry matching the basename (e.g.
foo.jpg).
Fonts and all other resources are always resolved from the archive root.
DecompressionStream API used for unpacking is available in all modern browsers (Chrome 80+, Firefox 113+, Safari 16.4+). No external ZIP library is required.With Tree
The <cxtf-tree> companion component renders a visibility-toggle tree panel linked to a <cxtf-view> by ID. It includes folder/group checkboxes, an image overlay section, a font list, and a built-in search box.
Connect them with the for attribute matching the viewer's id:
<div style="display:flex; border:1px solid #ccc;"> <!-- Tree panel: for= must match the cxtf-view id --> <cxtf-tree for="mymap" style="width:220px; flex-shrink:0;"></cxtf-tree> <!-- Viewer --> <cxtf-view id="mymap" src="mymap.cxtf" width="600" height="400" centered="true" interactive="true"></cxtf-view> </div>
<cxtf-tree> listens for the cxtf-ready event on the linked viewer. It can be placed anywhere in the document — it does not need to be adjacent to the viewer.
Toggling a checkbox in the tree calls node.visible = … on the parsed tree and then view.refresh() to redraw immediately.
cxtf-viewer.css is its companion CSS). Load that stylesheet in your page <head> for correct rendering.Live example
Events
All three events bubble and are dispatched on the <cxtf-view> element itself, so you can listen on a parent container. All three are dispatched asynchronously (via setTimeout), so listeners registered in a script loaded after cxtf-renderer.js are guaranteed to receive them.
| Event | detail | Description |
|---|---|---|
| cxtf-ready | { tree, view } | Fired after a successful parse and first render. tree is the parsed project tree; view is the component element itself. |
| cxtf-error | { src, filename, kind, detail } | Fired on fatal load or parse failure. kind is one of "not-found" (HTTP 404), "network" (other fetch failure), or "empty" (file loaded but parsed to an empty tree). src is the original URL; detail carries additional diagnostic information. The canvas displays an error message automatically. |
| cxtf-warning | { kind, message, paths } | Fired for non-fatal issues. Currently used when image assets fail to load; kind is "images", paths is an array of the resolved URLs that failed, and message is a human-readable summary. The canvas shows placeholder cross-outs on affected nodes. |
Usage example
const view = document.getElementById('mymap'); view.addEventListener('cxtf-ready', e => { const { tree, view } = e.detail; console.log('Loaded:', tree.meta.title ?? tree.meta.ofn); console.log('Dimensions:', tree.meta.dims); }); view.addEventListener('cxtf-error', e => { const { filename, kind } = e.detail; const msg = { 'not-found': `"${filename}" not found`, 'network': `"${filename}" could not be fetched`, 'empty': `"${filename}" has no renderable content`, }[kind] ?? `Error loading "${filename}"`; showError(msg); }); view.addEventListener('cxtf-warning', e => { if (e.detail.kind === 'images') console.warn('Failed images:', e.detail.paths); });
JavaScript API
After a cxtf-ready event (or once the element is in the DOM), the following properties and methods are available directly on the element reference.
Properties
| Property | Type | Description |
|---|---|---|
| .zoom | number (r/w) | Current zoom factor. Range 0.05 – 500. Setting triggers an immediate re-render. Each mouse-wheel step multiplies by 21/8 ≈ 1.091. |
| .focusPoint | { x, y } (r/w) | The point in CXTF coordinate space that maps to the canvas centre (when centered="true") or top-left origin. Setting triggers an immediate re-render. |
| .tree | object (r) | The parsed project tree. Available after cxtf-ready. Key sub-objects: tree.root (folder hierarchy), tree.meta (title, author, version, dims, …), tree.images. |
| .cxtfText | string (r) | The raw CXTF source text that was parsed — whether loaded via src or supplied inline. |
Methods
| Method | Description |
|---|---|
| .refresh() | Re-renders the canvas with the current view state. Call after manually modifying node.visible on tree nodes or any other state that affects rendering. |
| .setInteractive(bool) | Enables or disables mouse-wheel zoom, drag pan, and touch gestures at runtime. Cleans up any in-progress drag or touch gesture when disabling. Equivalent to toggling the interactive attribute. |
| .exportPng(filename?) | Renders the current view to a PNG at full canvas resolution and triggers a browser download. filename is optional — if omitted it defaults to the project's original filename (from the ofn command) with a .png extension. |
Usage example
const view = document.getElementById('mymap'); view.addEventListener('cxtf-ready', () => { // Zoom in 2× and centre on a specific point view.zoom = 2.0; view.focusPoint = { x: 100, y: 80 }; // Hide a specific folder by name function findNode(node, name) { if (node.name === name) return node; for (const child of node.children ?? []) { const found = findNode(child, name); if (found) return found; } } const labels = findNode(view.tree.root, 'Labels'); if (labels) { labels.visible = false; view.refresh(); } // Export to PNG document.getElementById('save-btn') .addEventListener('click', () => view.exportPng('mymap.png')); });
Known Limitations
The following CXTF commands are parsed but not yet rendered by the web component. Files using these features will load without error; the commands are silently ignored.
| Command | Description | Note |
|---|---|---|
| fh | Fill hatch pattern | GDI+ hatch styles — no direct Canvas 2D equivalent |
| ffg | Combined fill-style shorthand | Combines c + f + fg + fh; depends on fh |
| zr | Zoom-range visibility | Show/hide groups outside a min/max zoom range |
| J | Inline image element | Image placed inside a group (distinct from G background overlay) |
| cp | Extended line properties | Cap, join, dash — overlaps with w optional parameters |
| cg | Line/stroke gradient | No direct Canvas 2D equivalent for stroke gradients |
| triangle, quadrangle, ellipse, box | Primitive shapes (ElementType 60–63) | Parsed but not rendered |
| GGG contrast / mix | Image colour adjustment parameters | Opacity and inverted flag are applied; contrast, mix mode and per-channel curves are parsed but not rendered |
Examples
Command Reference
Enumeration Reference
Key Index
| Key ▲ | Name ▲ | Section ▲ | Remarks ▲ |
|---|