PTTJS — A Text‑Based Format for Complex Tables

PTTJS (Plain Text Table JavaScript) is a table format I created to solve my own pain points—and, judging by the feedback I’ve already received, I’m not the only one who has felt the limitations of existing text‑table formats. A JavaScript library with a parser + serializer and an Obsidian plugin are already available. Goal The main goal of PTTJS is to provide a text format that can faithfully store complex tables—far beyond what CSV or Markdown can handle—while still remaining human‑readable. Motivation I tolerated the shortcomings of other formats for a long time, but eventually the trade‑offs became impossible to ignore. Key drivers were: Feeding richer tables to LLMs. Documents often contain intricate, merged‑cell tables that can’t be flattened to CSV/Markdown, forcing us to reach for heavier multimodal models. Extracting tables via CV into plain text, not into a deeply nested JSON blob that’s unreadable until you re‑render it. Letting an LLM manipulate an entire table natively—rows, columns, formulas—without shoe‑horning everything through Google Sheets or Excel. Opening tables without special software. Most tables end up trapped in XLS(X) or ODT; PTTJS keeps them plain text. Editing complex tables in plain‑text tools like Obsidian. Personal dislike of Google Sheets/Excel (surely I’m not the only one!). the problem is indicated in points 1 and 2, the format is recognized normally and inserted into the text Format Overview The very first line is always an annotation: |PTTJS 1.0|encoding=UTF‑8| Pages A table can span multiple pages: |(@P1|Page Name){ …table data… }| Page markers are optional; omit them and the whole table lives on a single page. Cells Every cell starts with | and ends with >: |H([1|1]1|1|@C1)> H — optional marks a header cell ([X|Y]) — zero‑based cell index (optional; auto‑filled if absent) (X|Y) — cell span (defaults to 1|1; always declared in the top‑left merged cell) (@ID) — cell id for references Row ends with: < { }) must be URL‑encoded: \n → %5Cn | → %7C > → %3E < → %3C { → %7B } → %7D The library provides escapeValue / unescapeValue helpers. Scripts >>>SCRIPT …typings, formulas, styling… Make & Model080XXX02|>2005|>LEXUS RX 350787XXX16|>2015|>GEELY GC7871XXX05|>1997|>TOYOTA IPSUMA602XXX|>1996|>MITSUBISHI PAJERO890XXX02|>1997|>TOYOTA LAND CRUISER PRADO216XXX13|>2007|>DAEWOO NEXIAPlate Number|H([1|0])>Year|H([2|0])>Make & Model080XXX02|([1|1])>2007|([2|1])>LEXUS RX 350Plate Number|H(2|1)>Vehicle Data|H>|H>Year|H>Make & Model080XXX02|>2007|>LEXUS RX 350Plate Number|H([1|0])>Year|H([2|0])>Make & Model080XXX02|([1|1])>2007|([2|1])>LEXUS RX 350Average Year|([1|8])>2003>>SCRIPT (1|1,1|6)=>NUMBER(2,' ') (1|8)=DIV(SUM(1|1,1|6),COUNT(1|1,1|6)) (0|8:8)

May 11, 2025 - 19:16
 0
PTTJS — A Text‑Based Format for Complex Tables

PTTJS (Plain Text Table JavaScript) is a table format I created to solve my own pain points—and, judging by the feedback I’ve already received, I’m not the only one who has felt the limitations of existing text‑table formats.

A JavaScript library with a parser + serializer and an Obsidian plugin are already available.

Goal

The main goal of PTTJS is to provide a text format that can faithfully store complex tables—far beyond what CSV or Markdown can handle—while still remaining human‑readable.

Motivation

I tolerated the shortcomings of other formats for a long time, but eventually the trade‑offs became impossible to ignore. Key drivers were:

  1. Feeding richer tables to LLMs. Documents often contain intricate, merged‑cell tables that can’t be flattened to CSV/Markdown, forcing us to reach for heavier multimodal models.
  2. Extracting tables via CV into plain text, not into a deeply nested JSON blob that’s unreadable until you re‑render it.
  3. Letting an LLM manipulate an entire table natively—rows, columns, formulas—without shoe‑horning everything through Google Sheets or Excel.
  4. Opening tables without special software. Most tables end up trapped in XLS(X) or ODT; PTTJS keeps them plain text.
  5. Editing complex tables in plain‑text tools like Obsidian.
  6. Personal dislike of Google Sheets/Excel (surely I’m not the only one!).

the problem is indicated in points 1 and 2, the format is recognized normally and inserted into the text

the problem is indicated in points 1 and 2, the format is recognized normally and inserted into the text

Format Overview

The very first line is always an annotation:

|PTTJS 1.0|encoding=UTF‑8|

Pages

A table can span multiple pages:

|(@P1|Page Name){
    …table data…
}|

Page markers are optional; omit them and the whole table lives on a single page.

Cells

Every cell starts with | and ends with >:

|H([1|1]1|1|@C1)>
  • H — optional marks a header cell
  • ([X|Y]) — zero‑based cell index (optional; auto‑filled if absent)
  • (X|Y) — cell span (defaults to 1|1; always declared in the top‑left merged cell)
  • (@ID) — cell id for references

Row ends with:

<|

If a row is otherwise empty but you still have rows below it, include at least one empty cell: |><|.

Forbidden characters inside cell content (\n | > < { }) must be URL‑encoded:

\n  → %5Cn
|   → %7C
>   → %3E
<   → %3C
{   → %7B
}   → %7D

The library provides escapeValue / unescapeValue helpers.

Scripts

>>>SCRIPT
…typings, formulas, styling…
<<