You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
LaTeX2JS accepts a dialect of PSTricks that is partly a deliberate extension and partly accident, and today the two are indistinguishable. A document cannot say which one it is written in, so the extensions are invisible to a reader, unenforceable by a test, and impossible to tell apart from a bug.
This proposes making the dialect explicit and declared, fixing the accidents, and recording the remaining differences as decisions rather than surprises.
Every count below was measured against packages/latex2js/test/corpus (33 files) and verified against real PSTricks via tools/pstricks-conformance.
1. Declare the dialect
Add a \psset key, since \psset is already the scoped-settings mechanism:
\psset{dialect=latex2js} % or: mathapedia
Default pstricks. A document that does not declare a dialect is read as PSTricks, and anything outside that spec is a diagnostic. The extensions stay fully supported — they just have to say so.
The point is signalling. Today \psplot[algebraic]{-4}{4}{pow(x,2)} looks like ordinary PSTricks and is not; under this change it either declares itself or gets told.
What the flag turns on
Construct
PSTricks
LaTeX2JS dialect
\userline, \uservariable, \slider
do not exist
97 uses across 13 files — the interactive core, and the reason this project exists
plot bodies
RPN PostScript (x x mul)
infix (x^2), always
pow(a, b)
no such function, only ^
18 uses in 3 files
log(x)
base 10
natural log — 4 uses in 1 file
plot bounds
literal numbers
expressions over variables — 18 uses
plotpoints=1
rejected, minimum is 2
one sample — 3 uses
bare option flags ([algebraic])
syntax error
treated as true — 44 uses in 10 files
starred shapes (\psframe*)
fill with linecolor
honour fillcolor
colour names
xcolor palette
CSS names (lightblue) — 28 uses
15 corpus files need the flag. That refactor is mechanical and belongs in the same change as the feature, so the corpus proves the mechanism.
Migration
latex2js.com serves a checked-in bundle, so flipping the default breaks published content the moment it ships. Suggested sequencing:
Ship the key with the diagnostic active but the old lenient behaviour intact, so nothing breaks and every affected document is named in the console.
Flag the corpus and the site content.
Flip the default to pstricks in the next major.
2. Silent wrongness — fix regardless of dialect
These are not extensions. They are inputs that produce a plausible wrong picture and no error, which is the pattern behind nearly every defect found in #26.
2.1 X/Y turn NaN into 0
packages/utils/src/index.ts — both transforms return 0 on a non-finite input after a console.warn. A NaN coordinate therefore becomes a real point at the origin, so a broken plot renders as a flat line pinned to the axis rather than failing.
\psplot{-2}{2}{x x mul} — a perfectly ordinary PSTricks body — does exactly this today.
This one masks the others. Worth doing first.
2.2 Three options parsed and ignored
Option
Uses
Consequence
arrowscale
28
arrowheads are a hardcoded var d = 8; 1.1× and 1.5× both render identically
plotstyle
3
plotstyle=dots draws nothing — the tangent-point dots are missing from every picture in graph.tex, and present in the PSTricks reference
showorigin
6
origin tick not suppressible (currently masked: all 6 uses pair it with labels=none)
2.3 Pi is undefined
MATH_FUNCTIONS defines pi, PI and π — but not Pi, which is pst-plot's own spelling. Pi evaluates to undefined → NaN → §2.1 turns it into a flat line. Verified against PSTricks, where Pi is 3.14159. Nothing in the corpus uses it yet, so this is latent. One line.
2.4 Unresolvable plot bodies should be diagnostics
The parser already carries a diagnostics channel with line and column. A plot body that yields no finite value should use it instead of drawing something.
3. Coverage gaps
\psecurve has zero corpus coverage. Implemented, never exercised by any example or stress case.
plotpoints=1 in graph.tex (3×) is invalid upstream. Meaningful in the LaTeX2JS dialect once §2.2 lands, so it needs the flag rather than a fix.
4. Decisions to record, not fix
These are genuine forks where the lenient reading is defensible. They should be written down in tools/pstricks-conformance/README.md and, where they are dialect behaviour, gated behind the flag.
Starred shapes honour fillcolor. Every corpus use passes one and plainly means it — the bar chart wants blue bars, not black.
log is natural log.graph.tex plots derivatives of 2^x, whose derivative is 2^x·ln(2). The author wrote log meaning ln, so LaTeX2JS draws the mathematically intended curve and PSTricks would draw the wrong one. Worth keeping — but as a declared choice.
CSS colour names, including green = #008000 where LaTeX's green is #00FF00.
Document typesetting: sections, theorems and equations are unnumbered; theorem headings are block rather than run-in; footnotes are inline superscripts. Numbering is the one worth revisiting, since it is what makes a document cross-referenceable.
src/grammar/parser.js is copied verbatim by copy:grammar, not compiled. It is ES2015 against a repo targeting ES2020, so it is harmless today — but it bypasses tsc, so if the target is ever lowered to reach older browsers the parser will silently not be downlevelled and will become the floor, with nothing to indicate why. Either build it like everything else or emit it as ESM so tsc sees it.
Suggested order
§2.1 — stop coercing NaN to 0. It hides everything else.
§2.2, §2.3 — the ignored options and Pi. Small, visible, no design questions.
§1 — the dialect key, plus flagging all 15 corpus files.
§3 — psecurve coverage.
§4 — write the decisions down.
§5 — the build trap.
Steps 1–2 are strictly fixes and could land on their own. Step 3 is the one that needs agreement on the default and the migration window.
The conformance job added in #26 already guards this: every example is rendered with real PSTricks on each PR, and a picture that stops compiling fails the build.
LaTeX2JS accepts a dialect of PSTricks that is partly a deliberate extension and partly accident, and today the two are indistinguishable. A document cannot say which one it is written in, so the extensions are invisible to a reader, unenforceable by a test, and impossible to tell apart from a bug.
This proposes making the dialect explicit and declared, fixing the accidents, and recording the remaining differences as decisions rather than surprises.
Every count below was measured against
packages/latex2js/test/corpus(33 files) and verified against real PSTricks viatools/pstricks-conformance.1. Declare the dialect
Add a
\pssetkey, since\pssetis already the scoped-settings mechanism:Default
pstricks. A document that does not declare a dialect is read as PSTricks, and anything outside that spec is a diagnostic. The extensions stay fully supported — they just have to say so.The point is signalling. Today
\psplot[algebraic]{-4}{4}{pow(x,2)}looks like ordinary PSTricks and is not; under this change it either declares itself or gets told.What the flag turns on
\userline,\uservariable,\sliderx x mul)x^2), alwayspow(a, b)^log(x)plotpoints=1[algebraic])\psframe*)linecolorfillcolorlightblue) — 28 uses15 corpus files need the flag. That refactor is mechanical and belongs in the same change as the feature, so the corpus proves the mechanism.
Migration
latex2js.comserves a checked-in bundle, so flipping the default breaks published content the moment it ships. Suggested sequencing:pstricksin the next major.2. Silent wrongness — fix regardless of dialect
These are not extensions. They are inputs that produce a plausible wrong picture and no error, which is the pattern behind nearly every defect found in #26.
2.1
X/YturnNaNinto0packages/utils/src/index.ts— both transforms return0on a non-finite input after aconsole.warn. ANaNcoordinate therefore becomes a real point at the origin, so a broken plot renders as a flat line pinned to the axis rather than failing.\psplot{-2}{2}{x x mul}— a perfectly ordinary PSTricks body — does exactly this today.This one masks the others. Worth doing first.
2.2 Three options parsed and ignored
arrowscalevar d = 8; 1.1× and 1.5× both render identicallyplotstyleplotstyle=dotsdraws nothing — the tangent-point dots are missing from every picture ingraph.tex, and present in the PSTricks referenceshoworiginlabels=none)2.3
Piis undefinedMATH_FUNCTIONSdefinespi,PIandπ— but notPi, which is pst-plot's own spelling.Pievaluates toundefined→NaN→ §2.1 turns it into a flat line. Verified against PSTricks, wherePiis 3.14159. Nothing in the corpus uses it yet, so this is latent. One line.2.4 Unresolvable plot bodies should be diagnostics
The parser already carries a diagnostics channel with line and column. A plot body that yields no finite value should use it instead of drawing something.
3. Coverage gaps
\psecurvehas zero corpus coverage. Implemented, never exercised by any example or stress case.plotpoints=1ingraph.tex(3×) is invalid upstream. Meaningful in the LaTeX2JS dialect once §2.2 lands, so it needs the flag rather than a fix.4. Decisions to record, not fix
These are genuine forks where the lenient reading is defensible. They should be written down in
tools/pstricks-conformance/README.mdand, where they are dialect behaviour, gated behind the flag.fillcolor. Every corpus use passes one and plainly means it — the bar chart wants blue bars, not black.logis natural log.graph.texplots derivatives of2^x, whose derivative is2^x·ln(2). The author wrotelogmeaningln, so LaTeX2JS draws the mathematically intended curve and PSTricks would draw the wrong one. Worth keeping — but as a declared choice.green=#008000where LaTeX'sgreenis#00FF00.psaxeslabels default on (added in PSTricks semantic layer + conformance harness against real PSTricks #26 — changes 5 existing diagrams) and grid numbers opt-in (an SVG is clipped to the picture bounds, so an outside label would be invisible).5. Latent trap
src/grammar/parser.jsis copied verbatim bycopy:grammar, not compiled. It is ES2015 against a repo targeting ES2020, so it is harmless today — but it bypassestsc, so if the target is ever lowered to reach older browsers the parser will silently not be downlevelled and will become the floor, with nothing to indicate why. Either build it like everything else or emit it as ESM sotscsees it.Suggested order
NaNto0. It hides everything else.Pi. Small, visible, no design questions.psecurvecoverage.Steps 1–2 are strictly fixes and could land on their own. Step 3 is the one that needs agreement on the default and the migration window.
The conformance job added in #26 already guards this: every example is rendered with real PSTricks on each PR, and a picture that stops compiling fails the build.