Skip to content

docs: update all CLAUDE.md files to reflect current codebase state#1

Open
neerajs71 wants to merge 175 commits into
claude/create-hello-world-repo-FpvYLfrom
claude/general-session-OBasr
Open

docs: update all CLAUDE.md files to reflect current codebase state#1
neerajs71 wants to merge 175 commits into
claude/create-hello-world-repo-FpvYLfrom
claude/general-session-OBasr

Conversation

@neerajs71

Copy link
Copy Markdown
Owner

The project has grown from a simple Hello World into a full well-data
visualization app with DLIS/LAS/WSON viewers, a tab system, app registry,
and Google Drive integration. All CLAUDE.md files now document the actual
current architecture, components, state management, and conventions.

https://claude.ai/code/session_0124NnsMao3HQF3u2smci3Ho

claude added 30 commits March 24, 2026 23:05
The project has grown from a simple Hello World into a full well-data
visualization app with DLIS/LAS/WSON viewers, a tab system, app registry,
and Google Drive integration. All CLAUDE.md files now document the actual
current architecture, components, state management, and conventions.

https://claude.ai/code/session_0124NnsMao3HQF3u2smci3Ho
…y to well schematic

- Display Options popup: To Scale/Autoscale, Directional/Straight, X/Y/Dia Scale sliders, Preserve Aspect, Hide/Show Plot
- Edit panels for Open Hole, Cased Hole, Cementing, and Formation Strata with add/edit/delete
- Updated toolbar with section toggles and edit buttons
- Save/Download button to export edited WSON files
- Responsive display controls update SVG rendering in real-time

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Adds minimum-curvature survey calculation and directional SVG rendering:

- WellDirection class: minimum-curvature algorithm converts (MD, Inc, Az)
  survey stations to (Northing, TVD) using ratio-factor method
- buildDirPath(): generates directionally-warped SVG polygon paths for
  symmetric well sections (open hole, casing, completions)
- buildDirSide(): generates one-sided annular polygons for cement fill
  between borehole wall and casing string
- geo derived now extracts wellProfile/survey data from WSON, builds
  WellDirection instance, computes canvas extents from max deviation
- dirAxis: curved SVG centerline following wellbore trajectory
- syD(): depth → SVG-y using TVD instead of MD in directional mode
- Directional toggle disabled with indicator when no survey data found
- Canvas width auto-expands to fit horizontal well deviation

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
…c endpoint

- Add /api/schematic POST endpoint with pure-JS arc geometry (no turf dependency):
  controlSegment, buildSegments, autoNodes DTX with shoelace area formula
- Port WellDirection class to match dlis exactly: dirWarp([x,y]) uses slerp
  between q1u/q2u for proper arc interpolation, getPerpendicular2D for offsets
- Add txPoint() unified coordinate transform covering all 4 modes:
  straight/directional × normal/autoscale
- Fix canvas extent calculation: replace wellDir.getPos() with wellDir.dirWarp([0,md])
- Handle dlis config.* nested WSON format (openHole, casedHole, etc.)
- Build verified clean

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- geo derived now uses getSrc() matching fetchDirData — fixes dlis config.* format
- completions _top/_bot support both top/bot absolute depths and cursor+length format
- fetchDirData nodes handle completions with top/bot or length, perforations guarded
- Add default node [0, maxDepth] when no completions/perfs found (matches dlis)
- autoNodes: skip zero-length intervals, guard against Infinity weights

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- perfArrows rewritten to use txPoint — handles directional arc-slerp + autoscale DTX
- wellDir and dtx exposed from geo derived for use in template
- Perforation arrows correctly offset perpendicular to the well in directional mode

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
…mode

- jsonToSvgContent now builds paths in raw coords (diameter inches, depth meters)
  then applies txPoint per-point — matches dlis buildComponent.ts approach
- hasDir, wellDir, dtx, autoScale from geo passed through to transform function
- Component shapes now follow arc-slerp path in directional mode + respect DTX

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Initial tree only loads 2 levels; recursively fetch subfolders
to find first file of each target type regardless of depth.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Move deep Drive search to /api/dev-tabs endpoint — single
client round-trip instead of many sequential client fetches.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Single search query per extension — instant instead of many
sequential folder fetches across deep directory tree.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
static/activeTabs.json lists filenames to search on Drive and open
on load. Edit the file to change which tabs appear automatically.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Matches dlis approach: find activeTabs.json in Drive workspace folder,
parse tabs entries, resolve each file ID by name search, return for
auto-opening on load.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Watches datasourceStore.tree, traverses path with lazy folder loading,
calls tabStore.openFile matching exact sidebar-click behaviour.
Hardcoded paths live in src/lib/samples/index.js.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
…-style edit panels

- Add reusable FloatingPanel component (draggable, frosted glass, gradient header)
- Collapse all layer toggles+edit buttons into a single Layers toolbar button
- Layers panel shows toggle switches + edit pencil for each layer
- Display Options and Edit panels now use FloatingPanel (draggable, resizable)
- Toolbar reduced to 3 buttons: Info | Layers | Display

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Module-level variable survives route transitions — sample tabs
open once per browser session, not on every page remount.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Module-level Map caches displayOpts + layer visibility per tab.id.
Directional mode, scale settings and layer toggles now survive
tab switching and navigation.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Replace four separate edit FloatingPanels with a single tabbed
'Schematic Editor' floating panel (OH | CH | Cement | Strata tabs).
Clicking ✎ in the Layers panel opens the editor at the right tab.
Added Edit toolbar button to toggle the editor directly.
Enter key saves inline row edits; compact dlis-style table design.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Adds a 5th tab ('Completions') to the unified schematic editor FloatingPanel.
Follows dlis PopupCompletionsEditor pattern:
- Search bar filters by description/tool_comp with count display
- Card list shows description, tool_comp, OD/length/weight, joints info
- ↑/↓ reorder buttons, ✎ edit, ✕ delete per card
- Inline add/edit form (2-col grid, blue-50 bg, Enter-to-save)
- Fields: description, tool_comp, OD, OD multiplier, length, weight,
  no. joints, avg joint length
- Completions layer row ✎ button now links to comp tab

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- Move completions editor out of schematic editor into its own
  FloatingPanel (400px wide, opens from toolbar ⚙ button)
- Typeahead dropdown appears below search input while typing,
  showing matching completions as compact rows (description + tool_comp/OD/length)
  clicking a row jumps straight to its inline edit form
- Full list always visible below, with ↑↓ reorder, ✎ edit, ✕ delete
- Active edit row highlighted blue in the list
- Remove 'comp' tab from schematic editor tabs

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- Install xlsx package
- POST /api/schematic { action: 'filtercomps', q } loads comp_list.xlsx
  from static/ at server startup; multi-word search against search_string
  column (all words must match); returns up to 30 items
- Completions Editor search now calls the API (200ms debounce)
  and shows a dropdown of catalog matches with a 'Catalog — click to
  pre-fill form' header; selecting an item populates the Add form fields
  (description, tool_comp, od, od_multiplier, length, weight, joints)
- Falls back gracefully when comp_list.xlsx is absent
- Place comp_list.xlsx in static/ to enable catalog search

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
57 completion components with fields: comp_id, category, sub_category,
description, od, length, weight, company, grade, tool_comp, search_string, etc.
Powers the filtercomps API for catalog search in the Completions Editor.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
claude added 30 commits April 5, 2026 07:28
interactivity() must be called inside a Canvas child component, not at
page script level. Removing it since the test page doesn't need click
interaction on 3D objects.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Threlte requires OrbitControls to be a child of a Camera component,
not a sibling.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- Extend dgeo format with `operator` field per horizon ("none"|"RA"|"RAI"|"RB"|"RBI")
- DgeoApp: operator selector buttons in horizon list strip (5 small buttons per horizon)
- DgeoApp: SVG line styling by operator — RA/RAI=dashed, RB/RBI=bold, none=default
- DgeoApp: addHorizon/initDefault/loadFile/toJSON all handle operator field
- manifoldSolid.js: RA/RAI clipping phase using manifold.intersect() before subtract loop
  - RA: clips all shallower manifolds where the horizon cuts up through them
  - RAI: clips only the immediate shallower neighbour
  - RB/RBI: no change needed (standard subtract already creates correct channel body)
- W1_geology.dgeo sample updated with operator:"none" on all 6 horizons

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- Vertical panel (196px) replaces horizontal strip; horizons shown in
  user-defined array order = stratigraphic insertion order
- Up/Down arrow buttons per horizon to reorder (moveHorizon())
- Operator buttons (·/RA/RAI/RB/RBI) shown per horizon with tooltips
- Domain X/Depth inputs moved into the bottom of the panel
- 2D SVG bands still use depth-sorted horizons for correct visual display
- 3D view receives unsorted horizons so buildLayerSolids processes in order
- manifoldSolid.js: removed depth sort; processes in received array order
  with degenerate-layer guard (triVerts.length === 0)

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- Remove vertical side panel; replace with FloatingPanel triggered from toolbar
- Toolbar button (table icon) toggles the Horizons panel
- Panel shows tabular list: ↑↓ | color | name | ref depth (m) | operators | delete
- Ref depth input shows avg depth of horizon points; changing it shifts all points
- Up/down arrows reorder horizons in stratigraphic array order
- Operator buttons ·/RA/RAI/RB/RBI per row with descriptive tooltips
- Domain inputs restored to 2D view bar

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- Add operator reference legend at bottom of panel (·/RA/RAI/RB/RBI)
  with full descriptions of each geological operator
- Color-code active operator buttons: green=deposit, orange=RA/RAI, purple=RB/RBI
- Full tooltips on each operator button describing exact geometric effect
- Legend uses matching color coding for quick visual identification

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- Panel width: 520 → 340px (fits ~360px mobile screens)
- Table column widths tightened: ↑↓=22, swatch=16, depth=58, ops=112, del=16
- Row gap reduced 6→4px; padding tightened

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- Setting camera up to [0,0,-1] makes OrbitControls treat depth (Z) as
  the orbit axis, so horizontal drag rotates around the stratigraphic
  column as expected in geological viewing
- Position camera above and in front of the block (-Z = above surface)
- minPolarAngle=0.05 allows near-bird's-eye view
- maxPolarAngle=PI*0.72 limits tilt to ~130° to prevent flipping below
- Wider fov (50) and far=500 for better scene coverage

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Adds a 📏 Ruler toggle button in the 3D controls bar that displays
three calibrated rulers on the block edges:
- Depth ruler (right face, Z-axis): tick marks in metres
- Distance ruler (front-bottom edge, X-axis): tick marks in km
- Strike ruler (right-bottom edge, Y-axis): tick marks in km

Rulers use HTML labels via @threlte/extras HTML component so they
always face the camera and remain legible at any orbit angle.
Geometry is derived and disposed correctly on reactive updates.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Previously each horizon's solid spanned surface → horizon depth, so the
first solid appeared as a block at the top of the view. Geologically,
deposition fills from the horizon depth DOWN to the model base.

- Warp formula: vert[2] = hz + (WY - hz) * vert[2] / WY
  (top face → horizon depth, base face stays at WY)
- Subtraction flipped: mf[i].subtract(mf[i+1]) — shallower minus deeper
  gives the inter-horizon band; deepest layer = mf[last] alone (to base)
- RA/RAI intersect clipping still correct with bottom-up solids

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Adds smooth NURBS surface rendering alongside the existing bilinear
surfaces for comparison, and real-time intersection curves on a sliding
slice plane — all using WebGL (works on iOS and all browsers).

Architecture:
- nurbs/railsToNURBS.js: converts rails → NURBSSurfaceParams; pads to
  ≥4 rails by interpolating intermediate rails in the largest gap,
  ensuring cubic degree in the V (strike) direction
- nurbs/nurbsEval.glsl.js: GLSL fragment shader porting the WGSL
  compute shader from pyenthu/dlis — evaluates one NURBS surface point
  per fragment via Cox-de Boor basis functions
- nurbs/nurbsGpgpu.js: WebGL GPGPU evaluator using Three.js float
  render target + readRenderTargetPixels; caches vertex positions
- Dgeo3DView.svelte: 〜 NURBS toggle + Slice slider (0..strikeKm)
- Dgeo3DScene.svelte: NURBS mesh overlay at 38% opacity with wireframe,
  slice curves extracted per-frame from cached vertex grid (CPU O(res)),
  purple slice plane that moves with the slider

Existing bilinear surfaces unchanged; NURBS is additive overlay only.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- width: min(560px, calc(100vw - 16px)) — shrinks on narrow screens
- initial left position: 8px (was 40px) — stays on-screen on mobile
- rail strip max-width: min(280px, 40vw) — prevents header overflow

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
The $effect that built nurbsCache was both reading it (in the disposal
loop) and writing it. In Svelte 5 this creates an infinite re-run cycle
that freezes all UI event handling — buttons stop responding, including
Add Horizon and the horizons table toggle.

Fix: use untrack() around nurbsCache writes so the effect doesn't
register a read-dependency on the value it produces. Disposal is handled
exclusively by the separate cleanup effect which only reads in its
teardown function.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- Replace WebGL GPGPU NURBS evaluator with CPU Cox-de Boor (nurbsCpu.js)
  World-space coords (0–10) were being clipped to [0,1] by RGBA8 float
  texture fallback on many devices, causing surfaces to appear at the
  wrong position. CPU evaluation is ~5 ms for a 40×40 grid and works
  everywhere.
- Default rail count raised to 10 (configurable via "Rails:" number input
  in the 3D toolbar). addHorizon() now persists evenly-spaced rails;
  getRails() fallback also uses defaultRailCount for legacy horizons.
- Rename "Slice:" → "Y:" for the strike-direction slice slider.
- Remove untrack() hack; nurbsCache is now a clean $derived.by().

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- nurbsGpgpu.js: normalise control points to [0,1] before GPU upload,
  denormalise on readback — fixes surfaces appearing at top of block when
  the device falls back from FloatType to RGBA8 render targets (which
  clips world-space coords > 1.0)
- Dgeo3DScene: create NurbsGpgpu synchronously as a plain (non-reactive)
  variable + onDestroy cleanup; eliminates the reactive loop that was
  caused by gpgpu being $state (write in $effect → nurbsCache derived
  recomputes → disposal $effect triggers → repeat)
- NurbsCpu kept as silent fallback in the evaluator loop

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Adds NurbsWebGpu — a WebGPU compute shader NURBS evaluator using the
WGSL shader from pyenthu/dlis shaders/compute.wgsl.

Adaptations from the original:
- positionUniform removed (world-space control points, no offset needed)
- Output: 1 vec4/vertex (position only; Three.js computes normals on CPU)
- Bindings renumbered 0–4
- Control point index changed from U-major to V-major to match railsToNURBS()
  layout: cpIndex = (startV + l) * numControlPointsU + (startU + k)

Evaluator chain: WebGPU (async init) → WebGL GPGPU → CPU.
Dgeo3DScene uses an async $effect to await WebGPU evaluation; webgpuReady
$state triggers a cache rebuild once the device is ready. Falls back
silently to WebGL GPGPU or CPU on devices without WebGPU.

iOS 26 + Chrome confirmed WebGPU support — storage buffer output avoids
the RGBA8 float-clamping issue that affected the WebGL approach.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Remove sync read of nurbsCache from the !showNurbs branch — reading and
writing the same $state in one $effect causes Svelte 5 to re-run infinitely.
Geometry disposal is handled by the dedicated disposal $effect's cleanup fn.

Also add cancellation token so stale async evaluate() results are discarded
when the effect re-runs (e.g. showNurbs toggled off mid-flight).

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
adjustDepth() was only shifting h.points (the 2D profile) but not
h.rails[*].points. Since the 3D surface (both normal and NURBS) is
built from rail points, changing the depth in the Stratigraphic Column
had no visible effect in the 3D view.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
…i-1)

Two fixes in one commit:

1. manifoldSolid.js — rewrite layer stacking to match pyenthu/dlis geostore.ts:
   - Sort horizons DEEPEST FIRST (largest avg rail depth)
   - Layer[0] = solid[0] (basement, no subtraction)
   - Layer[i] = solid[i].subtract(solid[i-1]) for i > 0
     solid[i] shallower → larger; solid[i-1] deeper → smaller; result = band ✓
   - Remove RA/RAI/RB/RBI operator clipping (deposition operator only for now)
   - Add avgRailDepth() helper for reliable depth sorting

2. DgeoApp.svelte — adjustDepth() now shifts h.rails[*].points by the same
   delta as h.points, so changing the reference depth in the Stratigraphic
   Column moves the 3D surface too (already committed separately).

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- Add visible:true to all horizon objects (new + default)
- Add toggleVisibility(id) that flips h.visible and marks dirty
- Eye button in each row (blue=visible, grey=hidden) with SVG icons
- Dgeo3DScene: filter surfaces, NURBS cache, and solid block rendering
  by h.visible !== false so hidden horizons disappear instantly in 3D

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Wrap all NURBS meshes, slice curves, and slice plane in a T.Group offset
by WX+1.5 in X so the NURBS surfaces appear to the right of the geological
block rather than overlapping it. Also increase NURBS opacity to 0.75 and
add a ghost wireframe outline box behind the NURBS panel.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Prevents sweep self-intersections by ensuring every rail always touches
the left and right walls of the cross-section.

Drag locking (2D + 3D):
- onSvgMouseMove: identify leftmost/rightmost point by X value; lock its X
  to domX.min / domX.max while leaving Y (depth) free to move
- onDragMove (3D rail editor): same logic for rail control points

Geometry building (defensive):
- buildGridGeo: sort rail points by X before arc-length sampling, then
  snap sampled[0].x = domX.min, sampled[last].x = domX.max
- railsToNURBS: same sort + snap; domX now passed as opt
- buildSolidManifold (manifoldSolid.js): same sort + snap; domX threaded
  through buildLayerSolids → opts

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- DgeoApp: viewMode '2d' → '3d', showSolids false → true
- Dgeo3DView: showNurbs false → true

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
buildNurbsLayerSolids() in manifoldSolid.js:
- Takes the GPU-evaluated NURBS positions array per horizon
- buildNurbsSolid(): bilinearly interpolates the NURBS Z-grid inside
  manifold warp() — same closed-solid technique as buildSolidManifold
  but driven by the high-quality NURBS surface instead of the bilinear grid
- Sorts deepest-first by avg surface Z, then subtracts: solid[i] - solid[i-1]
- Same CSG deposition logic as the bilinear path

Dgeo3DScene.svelte:
- Adds id field to nurbsCache entries for identification
- New nurbsSolidBlocks $state + async $effect: rebuilds whenever
  nurbsCache or showSolids changes (with cancellation)
- NURBS T.Group shows solid blocks when Solidify is on, falls back to
  raw NURBS surfaces while building or when Solidify is off

Result: left panel = bilinear manifold CSG, right panel = NURBS manifold CSG

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
1. Dgeo3DView: editRailsSorted fallback generates defaultRailCount (10)
   evenly-spaced rails instead of 2 when a horizon has no saved rails

2. DgeoEditPopup: popup is now full-width (left:8px; right:8px; calc(100%-16px))
   and only draggable in Y — no more horizontal drift off-screen; editor
   body height raised to 300px

3. Dgeo2DRailEditor: clicking to add a point now inserts it at the correct
   X-sorted position instead of appending to the end; polyline uses a
   sorted-by-X copy (ptsLine) so it always draws left→right; drag/delete
   still use the original-order pts array for correct index tracking

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
Geometry builders (buildGridGeo, railsToNURBS, buildSolidManifold):
- Remove X-sort on rail points before sampleArcLength — arc-length order
  is now preserved so folds that double back in X render correctly
- Endpoint snap stays, but keyed to array index 0 / last, not min/max X

Drag locking (2D + 3D):
- Endpoint detection now uses array index 0 and n-1 (not min/max X find)
- First point always locked to domX.min, last to domX.max; middle points free

Dgeo2DRailEditor:
- onSvgClick: remove X-sort; insert new point between the two consecutive
  neighbours whose segment midpoint is closest to the click position
- ptsLine removed; polyline draws in arc-length (insertion) order so folds
  are visible in the editor
- pts stays in original order for drag/delete index tracking

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
polyStr() and bandPath() now use insertion/arc-length order matching the
underlying data. The {@const sorted} template variable is gone; label
placement uses the last point (right wall endpoint) directly.

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
- MAX_CP 64→512, MAX_KNOT 16→40 in GLSL shader (supports 36 U × 14 V)
- nurbsGpgpu.js: pre-allocate 512 CP uniforms, knot arrays of 40
- nCtrlU now derived from actual rail point count (clamped to 36) instead
  of the hardcoded 8, so fold geometry with many points is faithfully captured

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
When clicking '+ Add horizon', a modal opens with 6 preset shapes:
  - Flat, Dome (anticline), Undulating (sinusoidal)
  - Fold (anticline-syncline), Fold forward (right-vergent overturned),
    Fold backward (left-vergent overturned)

Fold forward/backward presets generate points that actually double back
in X, creating genuine overturned fold geometry compatible with the
arc-length NURBS parameterization.

Each preset populates both points[] (2D cross-section) and rails[]
(3D, one rail per defaultRailCount position across strike).

https://claude.ai/code/session_012tQZKTp1FJbrKf8PsyVMLd
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.

2 participants