Explore finite element models in an interactive engineering viewport.
- Engineering viewport: orbits and zooms about the element under the pointer, pans, fits, and switches between standard camera views and projection modes.
- Model geometry: switches beam, truss and cable members, shells, nodes, supports, springs, couplings, mesh lines, grids, and global or element-local axes independently, in the model's declared coordinate system, and opens a model that lies in a plane along that plane rather than at the isometric corner.
- Section profiles: renders rectangular, circular, tubular, tee, polygonal, and thin-walled plated member sections with instanced meshes, greying out whatever part of a section a source says does not carry.
- Multiple graphics: stores several named graphics in one
.grvfile, added and deleted from the toolbar, each with its own camera, visibility, section rendering, appearance, and print region. - Native documents: participates in modified tabs, Save and Save As, external reloads, deletion state and conflicted-save handling, records every change in a private
TextBufferso Undo and Redo cover the whole view document, exposes named graphics to the navigation panel, and reports model details and geometry counts to the metadata inspector. - Live sources: rebuilds the scene when a source reports that its geometry changed, keeping the camera the view document holds.
- Analysis results: searches load cases, displays source-defined member quantities with signed diagrams, station values and extrema, and animates displacement fields with exact or automatic amplification, displacement colours, and GPU shell deformation. Hidden views stop drawing until they become visible again.
- Model filtering: browses actual model values with titles and element counts, creates ordered add and subtract rules over element number, element kind, and source dimensions, and combines them with a compact toolbar filter using model selector codes.
- Symbols and connectors: draws axial springs as helices, transverse springs as crossed in-plane helices, rotational springs as rings, and couplings as plain links; sizes every mark with one length in millimetres and can scale springs relative to the stiffest one.
To install graviss search for it in the Install pane of the Lumine settings, or run the command lumine --install lumine-code/graviss.
Commands available in .graviss:
graviss:fit-view: fit the complete model in the viewport,graviss:previous-graphic: activate the previous graphic,graviss:next-graphic: activate the next graphic,graviss:add-graphic: add a blank graphic after the active one and show it,graviss:delete-graphic: delete the active graphic, keeping at least one,graviss:choose-background: open the engineering-background picker,graviss:toggle-projection: switch between perspective and orthographic projection,graviss:retry-loading-model: retry a failed model load,graviss:view-isometric: use the isometric orientation,graviss:view-top: use the top orientation,graviss:view-bottom: use the bottom orientation,graviss:view-front: use the front orientation,graviss:view-back: use the back orientation,graviss:view-right: use the right orientation,graviss:view-left: use the left orientation,graviss:view-top-left: use the top-left orientation,graviss:view-top-back: use the top-back orientation,graviss:view-top-right: use the top-right orientation,graviss:view-top-front: use the top-front orientation,graviss:view-front-left: use the front-left orientation,graviss:view-front-right: use the front-right orientation,graviss:view-bottom-front: use the bottom-front orientation,graviss:view-bottom-back: use the bottom-back orientation,graviss:view-bottom-left: use the bottom-left orientation,graviss:view-bottom-right: use the bottom-right orientation,graviss:view-back-left: use the back-left orientation,graviss:view-back-right: use the back-right orientation,graviss:view-top-back-left: use the top-back-left orientation,graviss:view-top-back-right: use the top-back-right orientation,graviss:view-top-front-right: use the top-front-right orientation,graviss:view-top-front-left: use the top-front-left orientation,graviss:view-bottom-front-left: use the bottom-front-left orientation,graviss:view-bottom-front-right: use the bottom-front-right orientation,graviss:view-bottom-back-left: use the bottom-back-left orientation,graviss:view-bottom-back-right: use the bottom-back-right orientation,graviss:perspective-projection: use perspective projection,graviss:orthographic-projection: use orthographic projection,graviss:toggle-members: show or hide beam members,graviss:toggle-shells: show or hide shells,graviss:toggle-nodes: show or hide nodes,graviss:toggle-supports: show or hide support symbols,graviss:toggle-springs: show or hide springs,graviss:toggle-spring-stiffness-scaling: scale spring symbols relative to the stiffest spring,graviss:toggle-couplings: show or hide couplings,graviss:toggle-mesh: show or hide the mesh lines over shell surfaces,graviss:toggle-grid: show or hide the engineering grid,graviss:toggle-axes: show or hide the global axes,graviss:toggle-local-axes: show or hide element-local axes,graviss:toggle-section-rendering: switch between rendered sections and plain lines and surfaces,graviss:toggle-background-gradient: grade the background lighter towards the top, or leave it flat,graviss:save-as-image: render the active graphic and save it as a PNG,graviss:copy-to-clipboard: render the active graphic and copy it to the clipboard,graviss:select-print-region: drag a rectangle over the canvas to set the print region,graviss:set-print-region-from-view: use what the viewport currently covers as the print region,graviss:auto-select: frame the structure exactly,graviss:auto-select-with-border: frame the structure with a margin of two per cent of its longer side,graviss:enter-selection-mode: work the print region without holding the modifier,graviss:exit-selection-mode: hand every pointer back to the model,graviss:clear-print-region: drop the print region and cover the whole model again,graviss:background-auto: follow the active theme for the background,graviss:background-cloud: use the Cloud appearance,graviss:background-midnight: use the Midnight appearance,graviss:background-paper: use the Paper appearance,graviss:background-white: use the White appearance,graviss:move-left: move the camera left,graviss:move-right: move the camera right,graviss:move-up: move the camera up,graviss:move-down: move the camera down,graviss:rotate-left: rotate the camera left,graviss:rotate-right: rotate the camera right,graviss:rotate-up: rotate the camera up,graviss:rotate-down: rotate the camera down,graviss:zoom-in: move closer to the model,graviss:zoom-out: move farther from the model.
Commands available in lumine-workspace:
graviss:toggle-filter-panel: show or hide the panel that narrows which elements are drawn,graviss:toggle-results-panel: show or hide the panel that shows the analysis results,graviss:toggle-focus-filter-panel: focus the filter panel, or hand focus back to the model,graviss:toggle-focus-results-panel: focus the results panel, or hand focus back to the model.
Commands available in .graviss-panel:
graviss:focus-viewer: return focus to the model, leaving the panel open,graviss:move-rule-up: move the filter rule holding focus one place earlier,graviss:move-rule-down: move the filter rule holding focus one place later.
A .grv document stores view configuration and an optional source path. When the source is omitted, registered providers can resolve a supported model with the same basename. Graviss opens the view as a canvas; choose Text Editor from Open… in the tree view to edit the same file as JSON. Choose Graviss from New… to create an unsaved view, then use Open Model Source to select an existing model. New views contain no model data.
These files are meant to be written by hand and by other tools, so everything in one is optional — the extension is what makes it a view — and a file holds only what someone set. What is left out is worked out: a pane is named after its file, a graphic after its position, a view with no camera frames the model. A change writes down itself and nothing else, so a file kept short stays short.
The narrowest complete document is therefore {}, and a useful one is little more:
{ "source": "model.dat" }A graphic holds what is being looked at as well as how: filter states the panel's element rules, quickFilter adds an independent toolbar expression, and results states which load case is shown, at what amplification and under which cycle. These settings are per graphic rather than per file, so one document can hold an animated mode shape, a static dead-load case and an unfiltered overview side by side.
The Results panel follows the active model and graphic. Search by case number or name, narrow the list by case type, or step through it with Previous and Next. System shows the undeformed model. The status distinguishes the requested case from the result currently displayed; an unsuccessful read leaves the previous result available and offers Retry. Enter an exact non-negative amplification factor, choose a preset, or use Auto. Pause freezes the displayed frame and Play resumes from it. The Deformation slider shows the actual deflection factor: 0% to 100% for Positive, or −100% to 100% for Swing. Its thumb follows the deformation's smooth acceleration rather than advancing at a constant speed. Dragging pauses at the chosen deformation while preserving the cycle's direction for resuming. The period is entered in seconds; Colours |u| uses true displacement magnitudes independently of amplification.
An optional results.cyclePosition stores the position as a finite fraction from 0 to 1 of one complete cycle, rather than as the deformation slider's factor. Both endpoints are undeformed. thereAndBack reaches the positive full shape at 0.5; pingPong reaches it at 0.25 and the negative full shape at 0.75. A paused graphic without this field keeps the earlier behavior of showing the positive full shape. A playing graphic without it starts from zero. Pausing or seeking records the corresponding cycle position, and playback resumes from that stored point when the graphic is restored. The .grv results.period remains expressed in milliseconds.
Choose Member results in Results, then choose a category and quantity from the source's catalogue. The catalogue can include axial and shear forces, bending and torsional moments, warping bimoments, local displacements and rotations, bedding forces, stresses and discrete reactions; the source defines the available quantities and their units. Diagrams follow each member's local axes on the undeformed model, distinguish positive and negative values, preserve jumps, and include labels at ends and sampled extrema. Discrete results use separate ordinates. Automatic orientation follows the quantity's convention; choose local y or z and Flip to control the drawing explicitly without changing the reported signs. Auto scale fits the visible field; manual scale states metres of diagram height per displayed unit. Fill and labels can be switched independently. These settings belong to each graphic and survive saving and reopening.
The summary reports the visible minimum and maximum with member and station positions. Selecting a member shows its sampled values, including both sides of a jump and explicit unavailable values. Filters, hidden member layers and construction-stage activity also restrict diagrams and extrema. An empty field means unavailable data rather than zero; gaps are not bridged. Continuous quantities are joined linearly without extrapolation, so extrema refer to supplied stations rather than an assumed analytical distribution. Labels prioritize the selected member and global extrema; overlapping labels are hidden and no more than 300 are created, with the reduced count shown in the panel. Exported pictures include the diagrams and readable labels.
The Filter panel lists rules in order and offers the model's actual values, including declared values that match no elements. Choose a dimension, search its IDs or titles, select one or more values, then use Add or Subtract to append one rule. Searching and selecting values leave the filter unchanged until that action. Number takes an expression such as 1-10, 15, 1*, 11?? instead of listing every element number. More → Blank rule opens an expression row for manual entry. Each rule reports its own matches; In filter reports the final accepted elements independently of layer visibility. Reorder by the grip or the Up and Down buttons, remove a rule, or use Show entire model to clear the list. The last matching rule decides, so successive additions mean either set, rather than their intersection.
Numeric filter expressions support numbers, inclusive ranges, and digit patterns separated by commas or whitespace. Named expressions retain case-insensitive ID or title matching with * and ? patterns. JSON-quoted names select exact, case-sensitive IDs and keep spaces, commas, wildcard characters, and escaped quotes literal; the value picker writes this form automatically. For example, "Temporary works" names that one ID, while temporary* matches names or titles beginning with that word. An unreadable expression shows its error beside the field and leaves the last valid filter active.
The toolbar's Quick filter is an additional condition: an element must pass both it and the Filter panel's rules. Enter applies the draft; Escape restores the applied text. An invalid draft reports its error and leaves the last valid expression active. The × button clears only the quick filter. While it is active, the panel's reset button reads Clear panel filter and leaves the toolbar expression active; otherwise it reads Show entire model. The ? help lists the current model's selector codes. Each graphic stores its optional expression as quickFilter, for example "quickFilter": "G12-15;-Q1??1*". Restoring an invalid saved expression shows its error and admits no elements until it is corrected or cleared.
Quick-filter clauses are separated by semicolons. Each starts with an optional + or -, a selector code, and an expression; omitted signs mean addition. The last matching clause decides. A leading subtraction starts from the whole model, while a leading addition starts from nothing. One trailing semicolon is allowed; empty clauses elsewhere are errors. Codes are case-insensitive, and the complete leading run of ASCII letters must be a known code. Unquoted names therefore require a colon, such as SG:DECK or SG:deck*; quoted exact IDs may follow directly, such as SG"DECK". A semicolon inside a quoted ID remains part of that ID.
All whitespace is removed from quick input, including whitespace inside quotes, and comma-separated terms remain within one clause. Use a JSON escape such as SG"Temporary\u0020works" when an exact named ID contains a space. With model codes G for groups and SG for named sets, G12-15;-Q1??1* adds groups 12–15 then subtracts shells matching the number pattern, GB12 restricts group 12 to beams, and SG:DECK selects a named set. A bare provider selector such as G admits every element holding that dimension; a bare kind selector admits all members of that kind, including unnumbered ones. Number expressions match only elements that have numbers.
| Core code | Domain |
|---|---|
N |
All elements. |
B |
Beams. |
Q |
Shells. |
T |
Trusses. |
C |
Cables. |
S |
Springs. |
K |
Couplings. |
A graphic is identified by where it sits in graphics, and by nothing else, so nothing about it can collide or be misspelt. activeGraphic names the one to show as a position, counting from zero. It may carry an id and be named by that instead, which is easier to write by hand; an id is an alias rather than an identity, so two graphics may share one and the first wins.
Anything a graphic states is taken when it can be read and replaced by what leaving it out would have meant when it cannot — a camera that does not parse frames the model, an unknown appearance follows the theme. Only two things make a document unreadable rather than merely incomplete: a format or version naming something Graviss does not know, where reading it hopefully would be guessing. Such a file is not opened as a canvas at all; it opens as text, which is where it can be fixed.
A title names the model when someone wants it named, and most documents have no reason to: without one the pane is named after its file, extension included, exactly as the source of the same file is named. The two tabs then read alike and the icon is what tells the render from the source.
The canvas keeps its canonical JSON in a private TextBuffer, without creating or registering a hidden text editor. Clean external changes reload immediately. Changes that overlap unsaved work remain conflicted until the normal Lumine save flow resolves them.
The canvas parses configurations up to 8 Mi UTF-16 units, 100,000 JSON values and 128 nesting levels; geometry remains in its external model source. Larger configurations open in Text Editor. Invalid or oversized raw source retains its exact text, line endings and undo/redo history, including through session recovery; the canvas keeps the last valid model and refuses view changes until the raw configuration is repaired. A changed disk file cannot replace recovered unsaved source. Bounded small history records remain directly JSON serializable; larger records retain immutable roots for Lumine's session codec and portable captureState() API. Quick-filter input is checked against a separate 64 Ki UTF-16 budget before parsing; a rejected draft remains editable.
Graviss owns the canvas and every command. Source packages provide the graviss.source service and own only recognition, file or database access, translation, and session disposal — no package but Graviss creates a viewer or registers an opener.
The toolbar is laid out by the scope a control acts at: first the set of graphics — paging, adding, deleting — then the picture the active graphic composes (camera, projection, background), then its layers (what is drawn and how it is marked), and, held to the far end, the picture output beside what belongs to the document and the renderer. Every control stays on screen whatever the document holds; what cannot be done right now is disabled rather than gone.
Dragging with the left button turns the model about whatever is under the pointer when the drag begins, so the detail being examined stays where it was rather than swinging out of frame. A mark shows the pinned point for as long as the drag runs. Started over empty space, where there is nothing to pin to, the drag turns about the camera target as it always did. The wheel is anchored the same way, moving along the ray under the pointer so that whatever it is over stays where it is. An orthographic camera cannot move toward anything, so there the wheel narrows the framing instead and slides the camera across its own image plane to hold the same point still. Either way the notch is eased onto over a few frames rather than arriving in one step.
A rendered image covers the active graphic's print region: a window cut through the camera's view, stored as angles about the view axis rather than as fractions of any pane. The stored camera and the stored region determine the picture completely — no window enters the definition — so every pane size and a batch render produce the same picture. The frame is fixed on the screen under every camera action: orbiting, panning and scrolling recompose what stands inside it, which is how a picture is composed through it, and none of them can move the frame itself. Resizing the pane reveals and crops the view without rescaling it, and the frame holds its pixels with it, staying over the structure it marks; it reaches past the edges of a pane too small to hold it. Every gesture on the frame is held behind the command modifier — Command on macOS, Control elsewhere — so the model keeps every unmodified pointer: orbit, pan, pick and the wheel all reach it through the frame. Held, a press inside the frame moves it, on an edge or a corner resizes it, outside it draws a new one, and a right-click drops it. One gesture is one undo step. Enter Selection Mode latches the modifier on for anyone who would rather not hold a key. Without one the image covers the whole model with a margin of two per cent of its longer side — the whole of it, including whatever the viewport is cropping away, and measured from what is drawn rather than from where the nodes are, so a rendered section is never cut off. It is still the view on screen, reaching past its edges: the camera never moves, because moving it would change the perspective and the image would be taken from somewhere the viewport never was.
Restoring a window rebuilds its panes before it wires up the packages' services, so a .grv reopened from the last session is built while no provider is registered and briefly reports that there is none. It loads itself as soon as one arrives, keeping the camera the document holds.
Each session describes its capabilities before Graviss asks for geometry, and a source may report that its data changed so Graviss rebuilds the scene. Values are SI: lengths in metres, forces in newtons. See the service contract for the normalized model interface.
Override the public custom properties in your styles.css to adjust the toolbar, the engineering-axis colors, and the mark that shows where a rotation is pinned:
.graviss {
--graviss-toolbar-height: 40px;
--graviss-axis-x-color: #d9574f;
--graviss-axis-y-color: #3b9c61;
--graviss-axis-z-color: #3f88d8;
}
.graviss-orbit-pivot {
--graviss-pivot-size: 16px;
}graviss.source: consumed to discover, open, and read FEM models supplied by source packages.navigation.adapter: provided to expose named graphics to the navigation panel.launcher.providerversion1.0.0: provided throughprovideLauncher()to create an unsaved Graviss center item. Itscreate({signal})factory returns the live item without opening it or changing focus; the launcher owns placement.
Got ideas to make this package better, found a bug, or want to help add new features? Just drop your thoughts on GitHub. Any feedback is welcome!
