Skip to content

Selva Plugin plugin-v0.22.0

Latest

Choose a tag to compare

@github-actions github-actions released this 03 Oct 11:01

Added

Hidden tabs (schema 2.15.0)

  • Tabs take an optional visible flag, toggled with the eye button on a tab in the builder. A hidden tab never shows in the web UI; its inputs still solve with their current values.
  • A tab whose groups are all hidden (by visible: false or visibility conditions) is hidden too, and a side panel with no visible tabs collapses away. Saved schemas upgrade automatically; absent means visible.
  • Update Selva Cloud before installing this plugin on a Rhino.Compute server: an older Selva rejects 2.15 schemas.

Material Preset component (Selva > Display)

  • Outputs a ready material for a real finish: stainless steel brushed, aluminium mill finish, galvanised steel, weathered titanium zinc, copper, coil-coated (RAL), wood, concrete, glass, brass, titanium. Metal and concrete base colours are measured values from physicallybased.info. Wire it into a Display, or into Three Material's Base to override parts of it.
  • Materials carry an optional FinishStrength (wire finishStrength) that scales the brushed or rolled finish; 0 turns it off. Presets can set it; Three Material passes its Base's through.

Live solve channel

  • The plugin reports each solve while it runs: solveStarted, progress, diagnostics and solveEnded as SolveEvents. Locally they ride the WebSocket; on Rhino.Compute (VektorNode fork) the plugin POSTs them to the callback named in the request's selvaevents block, batched with a heartbeat. In plain Grasshopper they are dropped.
  • Abort from the web UI: a cancelSolve WebSocket message locally, the callback reply's abort flag on Compute. Either sets Grasshopper's abort flag, so the solve stops at the next component.
  • The plugin decides each solve's verdict once (SolveOutcome: diagnostics, blocked, aborted). Locally it travels on the outputs envelope as outcome; on Compute the fork returns it as the response's selva block. A blocked or aborted solve sends empty outputs, so the client clears the previous result.

Message component (Selva > Utilities, hidden)

  • Raises a remark, warning or error when Condition is false and passes Condition through as Passed. An error blocks the solve's outputs from reaching the web UI; downstream components still compute, so gate expensive work on Passed.
  • Level (Remark/Warning/Error) and Notify (Popup/Log) are integer inputs with named values on right-click. Log adds the message to the list without interrupting; errors always interrupt.

Report Progress component (Selva > Utilities, hidden)

  • Wired inline before a step, it passes Data through and shows Message with a progress bar in the web UI. The plugin derives the fraction from which reporters run this solution, weighted by each step's last timing, so authors never write one and the bar only moves forward.

Fixed

  • Changing a Value List from the web UI no longer solves the definition twice.
  • Upgrading an obsolete component keeps values internalized in its colour, file and other non-primitive inputs. They were dropped, so an upgraded Three Material with a set colour turned white.
  • Web Display's grain UVs (anisotropic materials) no longer tilt on coarse flat parts or squeeze texture on faces oblique to the grain, follow each leg of a mitred corner piece instead of running vertical, and are now in millimetres whatever the model unit.

Added

Prepare UI Inputs

  • New Selva > UI component, Prepare UI Inputs (Plugin/Selva.GH/Features/UIBuilder/Components/GH_PrepareUIInputs.cs). Registers existing Number Sliders, Value Lists, Boolean Toggles, and Panels by instance GUID, previews the contextual parameter (Get Number, Get Integer, Get Value List, Get Boolean, Get String) each one infers from its live data, and inserts it between the control and the inputs it drives - or beside a disconnected control - as one undoable, previewed operation. Existing compatible Get parameters are recognized and can be adopted, renamed, or repaired. Removal reverses the insertion and never deletes a node the component did not create or explicitly adopt.
  • Ported from a WASPer plugin prototype (Components/1.2_Studies/Sm06) per 00_Plans/SELVA_PREPARE_UI_INPUTS_PLAN.md; the classification and inference math live in Services/PrepareUIInputInference.cs, split out with no Grasshopper dependency so it is covered by unit tests in Plugin/Selva.Tests.

Changed

sourceComponentId is now batchId

  • The field was never "the component that made this mesh" — it is the batch's identity namespace, which with a mesh's originalIndex forms the key that survives a solve (hidden state, selection, per-object overrides). It is usually the producing Display's InstanceGuid, but a combined batch takes the combiner's id, and the old name actively misled there. "Which component produced this mesh" is the per-mesh gh:component attr instead.
  • Renamed in the C# API and in the SLVM EXTN chunk. The JSON wire name is unchanged (sourceComponentId in the values envelope and on mesh userData): it is the contract with published @selvajs/* releases and is baked into every pre-v3 blob, .gh archive and .slvm file. Containers written with the old EXTN spelling are still read, on both stacks, pinned by a regression test each side.

SLVM v3 — one chunked container for wire and file

  • The mesh payload is now an SLVM v3 chunked container (magic SLVM, fourcc chunks, unknown types skipped by length) — the same bytes on the wire, in .gh archives, and on disk as .slvm. It replaces three nested layers: the DMF1 file sidecar, the JSON metadata embedded in the geometry blob, and the duplicate copy of that metadata the old file carried (a 12,679-mesh scene shrinks from 3.05 MB to 1.33 MB on disk).
  • The object table is columnar and pays only for what's present: vertex/index windows are prefix sums (never stored), auto-numbered names cost one byte total, layers/names dedupe through a string pool, and per-mesh metadata is stored as sparse attr columns — the key once, then only the objects carrying it. Namespaced keys (gh:branch, ifc:guid, …) give hosts and users a first-class slot for per-mesh provenance.
  • Grasshopper concepts left the core format: sourceComponentId and the Rhino NURBS JSON behind curves now live in a namespaced EXTN "selva.gh" chunk a foreign reader can skip. Object identity now travels inside the container's own table, so Display From File no longer restamps it on load — its Id input is gone; see Obsolete components below.
  • Curves and points became core objects in the file: their polylines/positions are stored through the same quantize+delta codec as meshes (CRVS/PNTS chunks) instead of JSON double arrays. Data-URI textures are extracted into binary TEXR chunks and reconstructed on read.
  • Everything old still reads: DMF1 files, bare SLVA/SLVZ blobs in saved .gh files, and every geometry blob back to v1 — readers dispatch on the leading magic. New bytes are always SLVM v3, so the web app must run a matching @selvajs/visualization release.
  • The codec (reader/writer, container, identity) moved into its own Rhino-free Selva.Slva project, so it builds and tests independently of Selva.GH. See Selva.Slva/README.md.

WebDisplay → Mesh cast: bulk join, honest validity

  • Casting a Web Display into a Mesh param now appends the whole mesh sequence in one call instead of one Append per mesh — quadratic before, 27 s → 35 ms on a 12,679-mesh batch — and validates the joined mesh with IsValid instead of Faces.Count > 0, so a failed join fails the cast instead of leaking corrupt geometry downstream.
  • Degenerate faces produced by quantization (triangles thinner than one int16 step collapse to a line) are culled when meshes are rebuilt from a batch, so previews, casts and the new components below always hand Grasshopper valid meshes.

Added

Deconstruct Display component

  • Unpacks a Web Display into one Rhino mesh per entry in its mesh table — with names, layers and material colours as parallel lists — instead of forcing the single-mesh join. The route that preserves per-mesh identity on large batches.

Combine Display component

  • Collapses every branch of a Web Display tree into one payload on the same path: a branch holding five Displays becomes one. The tree structure survives, so a downstream Display To File writes one file per branch instead of one per item, and the viewer receives one payload per branch.
  • Merging is a real re-encode, not a concatenation. Materials dedupe across a branch, so Displays sharing a material collapse into one group — one draw call in the browser instead of several — and the geometry is re-quantized over the branch's union bounding box for a single optimal blob. Measured on two real scenes (6,043 + 12,679 meshes): 2.31 MB of separate payloads → 1.90 MB combined, in 0.7 s.
  • Each merged payload takes its own id (the component's, plus the branch path) for web pick identity, so every mesh records where it came from in the gh:component / gh:originalIndex metadata attrs — provenance survives the merge, and survives a second merge too. An unreadable input is skipped with a warning naming its branch instead of failing the whole combine.

Performance

WebDisplay: SLVA v4 — 28–50% smaller mesh payloads

  • The mesh wire format gained a fourth version. Its delta-filtered vertex, index and UV streams can now be stored as byte planes (all X deltas, then Y, then Z, low bytes before high) instead of interleaved values. Near-zero deltas turn the high planes into runs of zeros, so the DEFLATE pass compresses far better. Measured through the real writer: a welded 65k-vertex surface 144 KB → 104 KB (−28%), a 262k-vertex surface 636 KB → 409 KB (−36%), a 3000-part CAD scatter 116 KB → 58 KB (−50%). Cloud delivery multiplies each saving by 1.33×, since the payload is base64-encoded.
  • The layout is chosen per blob, by measurement. Neither layout wins everywhere: planar byte-split wins on locally-coherent geometry, but interleaved wins by up to 44% when a batch is mostly byte-identical repeated parts (an arrayed screw, an instanced facade panel), because it keeps each copy's bytes contiguous for DEFLATE's LZ77 window to match as one run. The crossover sits near 75–80% identical repeats — too close for a heuristic — so the writer trial-deflates both layouts and keeps the smaller, recording the choice in a flag bit. On every measured shape the emitted blob is now no larger than either fixed layout, and an instanced part-array is 3.5% of its quantized payload (was 4.6%).
  • The probe costs two extra CompressionLevel.Fastest DEFLATE passes over the vertex stream, and is skipped below 4,096 vertices. Encoding already runs on the component's background task, so this never blocks the solver thread. Decoding is unaffected — slightly faster, in fact, since there is less to inflate.
  • Blobs written by older plugin versions keep decoding unchanged: saved .gh files, .slvm mesh files and cached compute results. Frozen pre-v4 golden fixtures pin that on both the C# and TypeScript sides.
  • Quantization is untouched, so visual output is identical — this is a pure byte-layout change.

Obsolete components

  • Three Material (80CD38E5-BC9E-47E4-88EE-8F35B7E109CC → 31100A9A-AA13-43EF-9C2C-8F3C56BC6D68): appends optional Base, Mapping, Texture Size, Finish, Transmission and IOR inputs. Base takes a material to start from, such as a Material Preset; every wired input overrides its value. Mapping picks the texture coordinates: Surface (Rhino's), Part (along each part's grain, in mm, offset per part), World (box projection in mm) or Authored (the input mesh's own UVs in model units, such as flat-pattern positions from a sheet-metal unroll; Part when it has none). Texture Size is the real width one texture repeat covers, in mm. Finish adds procedural brushed or rolled streaks along the grain. Transmission and IOR are for glass. Color, Metalness, Roughness, Opacity and Transparent lost their persistent defaults so a base can fill them; unwired and without a base they fall back to the old defaults. Old definitions upgrade automatically.
  • Three Material (B7665E1A-C4CC-49D6-8EDB-4AAEF045D9A8 → 80CD38E5-BC9E-47E4-88EE-8F35B7E109CC): appends optional Reflection, Clearcoat, Clearcoat Roughness, Anisotropy, Anisotropy Rotation, Roughness Map and Normal Map inputs. Unwired, each stays off the wire and the viewer keeps its default. Reflection beats the look's value so a metal stays reflective in every look; Clearcoat replaces the automatic satin coat on metals. Anisotropy and the two maps make Web Display carry the mesh's texture coordinates; anisotropy is dropped for meshes that have none. Old definitions upgrade automatically.
  • Display From File (8B2E5C71-9A34-4F6D-B017-3C4D5E6F7A81 → B9FCCDF3-DBA3-47C0-BEAA-078ABFB92241): the Id input is gone now that SLVM v3 carries object identity in the container's own table, so loading no longer needs to restamp it. Old definitions upgrade automatically; the Id wire is dropped.

Upgraders

  • GH_ThreeMaterialUpgrader_To_0_22: 80CD38E5 → 31100A9A (appends six optional inputs).
  • GH_DisplayFromFileUpgrader_To_0_18: 8B2E5C71 → B9FCCDF3 (drops the Id input).
  • GH_ThreeMaterialUpgrader_To_0_21: B7665E1A → 80CD38E5 (appends seven optional inputs).