Skip to content

feat: implicit 2D curves + inequality/region shading (roadmap #1, #3)#77

Merged
ABCrimson merged 7 commits into
mainfrom
feat/wave1-implicit-inequalities
Jul 11, 2026
Merged

feat: implicit 2D curves + inequality/region shading (roadmap #1, #3)#77
ABCrimson merged 7 commits into
mainfrom
feat/wave1-implicit-inequalities

Conversation

@ABCrimson

Copy link
Copy Markdown
Owner

Summary

  • math-engine: first-class relational expressions — RelationalNode, parseRelationSystem (=, <, <=, >, >=, unicode variants, chained comparisons like 1 < x < 4, multi-relation systems), compileRelationField with slider-value binding
  • plot-engine: new 2d-relation plot type across all three backends — NaN-preserving adaptive scalar-field sampling with LRU cache, marching-squares boundary + fill triangulation, dashed strict-inequality boundaries, WebGPU per-pixel sign(F) region shading
  • web: Plot2D now uses the createAndInitBest2DRenderer factory (WebGPU → WebGL2 → Canvas2D); new 2D Relations tab on the plot page with multi-entry input, per-entry localized parse errors, preset chips, and slider reuse; plots.relation.* i18n in all 8 locales

Verification

  • math-engine 2242 tests, plot-engine 398 tests, web 297 tests — all green; typecheck + biome clean
  • Engine shading convention (F = lhs − rhs; < shades F<0, > shades F>0) independently probed end-to-end for flipped operand order, chained decomposition, unicode operators, slider binding, and NaN at singularities

Wave-1 roadmap items #1 and #3 (docs/ROADMAP.md).

🤖 Generated with Claude Code

ABCrimson and others added 6 commits July 10, 2026 19:32
… + parseRelationSystem + compileRelationField)

- RelationalNode in the branded AST with builder, guard, visitor support
- parseRelationSystem: mathjs-15.2-backed parsing of =, <, <=, >, >= with
  unicode ≤/≥ normalization, lone-= -> == rewriting, and chained
  1<x<2 decomposition into consecutive-pair relations; != throws ParseError
- compileRelationField: compiled lhs-minus-rhs scalar-field closure with
  NaN-on-failure semantics and slider-parameter binding
- relationDirection/isStrictRelation/isExplicitYRelation/explicitSideOf
  helpers for renderer routing and the web y=f(x) fast path
- evaluator visitRelational (1/0 with tolerant =); extractVariables handles
  relational strings; series.ts LaTeX visitor renders relations

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ality regions across all three backends

- New '2d-relation' PlotConfig (Plot2DRelationEntry/Plot2DRelationConfig,
  isRelationPlot; local RelationOperator union keeps the package free of any
  math-engine dependency); Plot2DImplicitConfig marked @deprecated
- utils/implicit-field: adaptive coarse(48²)-then-refine scalar-field
  sampling that PRESERVES NaN (fixes the fake-contour-at-singularity bug the
  old renderImplicit grid loops had by zeroing non-finite values),
  ScalarFieldCache (fn-identity+viewport LRU, 64 entries),
  combineIntersectionGrids (NaN-propagating min of dir-scaled layers)
- utils/marching-squares: NaN-corner cells are skipped; new
  marchingSquaresFilledTriangles (perimeter-walk polygon per cell, convex
  corner-chop fan triangulation, saddle center-average disambiguation)
- utils/dash: arc-length dashPolyline for GPU dashed boundaries
- WebGPU: PREREQUISITE FIX — shared last-write-wins drawUniformBuffer
  replaced by a 256-byte-aligned dynamic-offset ring buffer (one reusable
  bind group, per-draw slots, mid-frame growth, device-loss coverage); fixes
  multi-series plots all rendering in the final draw's color. New
  region-fill pipeline: per-pixel sign(F) shading over r32float
  texture_2d_array (manual bilinear textureLoad — no float32-filterable
  requirement; fwidth AA; bit-pattern NaN masking; in-shader mask
  multiplication for systems); renderRelation with grouped/intersection
  layer sets, dashed strict boundaries, explicit y=f(x) overlay
- WebGL2: renderRelation via combineIntersectionGrids +
  marchingSquaresFilledTriangles fills (new renderTriangles/renderLineList
  helpers), dashed strict boundaries; renderImplicit on the shared sampler
- Canvas2D: implements renderImplicit + renderRelation (batched Path2D
  fills, ctx.setLineDash boundaries) — implicit no longer throws in
  fallback mode
- Exports for the new surface; tests for sampler/cache/dash/filled
  triangles/NaN handling/type guards (398 tests green)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…actory

Switches Plot2D from a hardcoded WebGL2DRenderer to
createAndInitBest2DRenderer (WebGPU -> WebGL2 -> Canvas2D fallback) and
threads the new '2d-relation' PlotConfig type through viewport tracking,
the interaction controller, axis-label rendering, and the annotation
overlay so implicit-curve / inequality plots get pan, zoom, and
annotations for free.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes the UI gap for roadmap #1 (implicit curves, F(x,y)=0) and #3
(inequality/region shading) — the math-engine and plot-engine layers were
already complete, but nothing let a user type 'y > x^2' anywhere.

- RelationInput: a dedicated multi-entry input (one system per line, "Add
  Relation" pattern matching FunctionInput) that validates each entry via
  parseRelationSystem/isRelationalExpression and surfaces localized,
  per-entry parse errors inline without crashing.
- relation-config.ts: pure buildRelationConfig/buildRelationEntries helpers
  that turn valid RelationDefinitions into a Plot2DRelationConfig — chained
  comparisons (e.g. `1 < x < 4`) are grouped so the renderer intersects them
  into one band, while separate system entries each shade independently.
- New "2D Relations" tab on the plot page, wired the same way as the
  existing Cartesian/Polar/Parametric tabs: preset chips (circle, a region
  inequality, a two-relation system, a chained band), variable sliders for
  any extra parameters, and <Plot2D> fed the built config. Export is
  intentionally out of scope — PlotExportToolbar only samples ordinary
  functions, not implicit fields.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Genuine translations (not English placeholders) across all 8 locales for
the new RelationInput UI and tab label: labels, placeholders, per-entry
validity/error messages, empty state, helper text, and the plot title/
description. ICU-safe — French apostrophes use the typographic ' form.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ring

- relation-config.test.ts: buildRelationEntries/buildRelationConfig — single
  relation, a 2-relation system (separate shaded layers), chained-comparison
  grouping, invalid/empty entries skipped defensively, slider-value binding,
  per-entry styling, and full config assembly.
- RelationInput.test.tsx: renders per-entry fields, empty state, valid single
  vs. chained-band detection, localized inline errors for invalid syntax and
  non-relational input, add/remove/max-relations behavior.
- Plot2D.relation.test.tsx: smoke-tests the '2d-relation' branches added to
  Plot2D — renderer init via the mocked createAndInitBest2DRenderer, axis
  label threading, pan-driven viewport propagation through the real (GPU-free)
  Plot2DController, and renderer disposal on unmount.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nextcalc-pro Ready Ready Preview, Comment Jul 11, 2026 5:07pm

…ualities

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ABCrimson
ABCrimson merged commit f24f758 into main Jul 11, 2026
7 checks passed
@ABCrimson
ABCrimson deleted the feat/wave1-implicit-inequalities branch July 11, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant