Skip to content

Releases: vimaec/vim-web

1.00 beta

26 Mar 18:59

Choose a tag to compare

1.00 beta Pre-release
Pre-release

vim-web 1.0.0-beta.1

⚠️ Breaking Changes

See migration guide at the end

API Changes

  • createViewer is now async — Returns Promise<ViewerApi> instead of ViewerApi
  • viewer.settings removed — Use viewer.ui for runtime UI toggles
  • viewer.renderSettings — Outline, selection fill, transparency, and room rendering moved out of IsolationApi into a dedicated API
  • VimSettings.transparency removed — The load-time TransparencyMode option is gone. Use viewer.isolation.showTransparent for runtime control
  • IsolationSettings.transparency renamed to showTransparent

Peer Dependencies

  • React ^18.3.1 || ^19.0.0 required (was ^18.3.1)

✨ New Features

  • Reactive UI controls — Every UI panel toggle is now a StateRef you can read, write, and subscribe to
  • Configurable transparent opacity — Glass/window opacity is now adjustable (was hardcoded 0.25)
  • BIM parameter preloadingviewer.load({ url }, { prewarmBim: true }) eliminates the first-query delay
  • vim.load() is idempotent — Safe to call multiple times; clears previous geometry automatically
  • getElementFromUniqueId() — Look up elements by Revit unique ID string
  • hasGeometry vs hasMeshhasGeometry is true after VIM parsing; hasMesh is true after geometry is loaded
  • onGeometryLoaded signal — Fires after vim.load(subset) completes
  • Portal-based tooltips — Consistent styled tooltips everywhere, never clipped by overflow containers
  • Reactive control bar tooltips — Toggle buttons show contextual tips (e.g. "Disable Section Box" when active)
  • exports field in package.jsonimport 'vim-web/style.css' and import type { ... } from 'vim-web/bim'

⚡ Performance

  • BIM tree virtualization — Only visible rows are rendered. Handles 100k+ elements smoothly
  • BIM parameter caching — Entity table columns cached at the Vim level. Per-query cost reduced from ~300ms to <1ms
  • Debounced BIM info panel — 50ms debounce prevents main thread blocking during rapid selection
  • Tree click optimization — Selecting in the tree skips the expensive viewer→tree sync loop
  • Camera lerp fixonProgress(1) now fires before the callback is cleared

🏗️ Architecture

  • Headless BIM tree — Replaced react-complex-tree with @headless-tree/react. Full DOM control, no !important overrides, flat item list ready for virtualization
  • Clean tree data model — String IDs, semantic visibility (visible / partial / hidden), O(1) range lookups, parent-first ordering
  • Extracted tree hooksuseBimTree, useBimVirtualizer, useBimVisibility, useBimSelectionSync, useBimClickHandler
  • Native UI components — Side panel resize and context menu reimplemented without libraries (~30 lines each)
  • Tailwind CSS removed — All styling uses semantic CSS classes with design tokens
  • No linter/formatter — ESLint and Prettier removed. TypeScript compiler is the only build gate

📦 Dependencies

Removed (11)

react-tooltip · re-resizable · @firefox-devtools/react-contextmenu · react-complex-tree · ste-events · eslint · prettier · @typescript-eslint/* · postcss · tailwindcss · autoprefixer

Added (3)

@headless-tree/core · @headless-tree/react · @tanstack/react-virtual

Updated

Package From To
React 18.3 19.2
TypeScript 5.8 6.0
Vite 6.4 8.0
Three.js 0.171 0.183
vim-format 1.0.15-dev.5 1.0.16-dev.6

Result

407 → 133 installed packages (67% reduction)

=====================

Migration Guide: vim-web 0.5 → 1.0.0-beta.1

Install

npm install vim-web@beta

React 18.3+ still works. React 19 is also supported.

Breaking Changes

1. createViewer is now async

// Before (0.5)
const viewer = VIM.React.Webgl.createViewer(div, settings)

// After (1.0)
const viewer = await VIM.React.Webgl.createViewer(div, settings)

Same for Ultra:

const viewer = await VIM.React.Ultra.createViewer(div, settings)

2. viewer.settings removed

The SettingsApi (viewer.settings.update(), viewer.settings.register(), viewer.settings.customize()) no longer exists.

For UI visibility toggles, use viewer.ui:

// Before
viewer.settings.update(s => { s.ui.panelBimTree = false })
viewer.settings.update(s => { s.ui.panelControlBar = false })

// After
viewer.ui.bimTree.set(false)
viewer.ui.controlBar.set(false)

// Subscribe to changes
viewer.ui.axes.onChange.subscribe(visible => { ... })

// Read current state
const showing = viewer.ui.bimTree.get()

Available UI controls: logo, controlBar, bimTree, bimInfo, axes, performance, axesOrthographic, axesHome, cursorOrbit, cursorLookAround, cursorPan, cursorZoom, cameraAuto, cameraFrameScene, cameraFrameSelection, sectioningEnable, sectioningFitToSelection, sectioningReset, sectioningShow, sectioningAuto, sectioningSettings, measureEnable, visibilityClearSelection, visibilityShowAll, visibilityToggle, visibilityIsolate, visibilityAutoIsolate, visibilitySettings, miscProjectInspector, miscSettings, miscHelp, miscMaximise

For render settings (outline, selection fill, transparency), use viewer.renderSettings:

// Before
viewer.isolation.outlineEnabled.set(false)
viewer.isolation.selectionFillMode.set('xray')
viewer.isolation.showTransparent.set(false)

// After
viewer.renderSettings.outlineEnabled.set(false)
viewer.renderSettings.selectionFillMode.set('xray')
viewer.renderSettings.showTransparent.set(false)

3. VimSettings.transparency removed

The load-time TransparencyMode option ('opaqueOnly', 'transparentOnly', 'allAsOpaque', 'all') is gone.

// Before
viewer.load({ url }, { transparency: 'opaqueOnly' })

// After — control at runtime instead
viewer.load({ url })
viewer.renderSettings.showTransparent.set(false)

4. IsolationSettings.transparency renamed

// Before
const viewer = await VIM.React.Webgl.createViewer(div, {
  isolation: { transparency: false }
})

// After
const viewer = await VIM.React.Webgl.createViewer(div, {
  isolation: { showTransparent: false }
})

5. IsolationApi slimmed down

Render-related settings moved out of IsolationApi. The isolation API now only handles visibility:

// These still work on viewer.isolation:
viewer.isolation.showAll()
viewer.isolation.hideSelection()
viewer.isolation.isolateSelection()
viewer.isolation.autoIsolate.set(true)
viewer.isolation.showGhost.set(true)
viewer.isolation.ghostOpacity.set(0.5)

// These moved to viewer.renderSettings:
viewer.renderSettings.showTransparent
viewer.renderSettings.transparentOpacity
viewer.renderSettings.outlineEnabled
viewer.renderSettings.outlineQuality
viewer.renderSettings.outlineThickness
viewer.renderSettings.selectionFillMode
viewer.renderSettings.selectionOverlayOpacity
viewer.renderSettings.showRooms

New Features

BIM Parameter Preloading

Eliminates the ~300ms delay on the first property query:

// Option A: at load time
const request = viewer.load({ url }, { prewarmBim: true })

// Option B: manually after load
const vim = await request.getVim()
vim.prewarmBimCache()

Configurable Transparent Opacity

Glass/window opacity was hardcoded at 0.25. Now configurable:

viewer.materials.transparentOpacity = 0.5

New Element APIs

// Look up by Revit unique ID
const element = vim.getElementFromUniqueId('abc-123-def')

// Distinguish parsed geometry from loaded geometry
element.hasGeometry  // true after VIM is parsed (instances exist)
element.hasMesh      // true after vim.load() builds the mesh

// React to geometry loading
vim.onGeometryLoaded.subscribe(() => { ... })

Idempotent vim.load()

Safe to call multiple times — clears previous geometry automatically:

await vim.load()       // loads all
await vim.load()       // clears and reloads (no duplicates)
await vim.load(subset) // clears and loads subset

CSS Import

// Before — import path depended on bundler setup
import 'vim-web/dist/style.css'

// After — clean named export
import 'vim-web/style.css'

BIM Types Import

// Type-only import for BIM data types
import type { ... } from 'vim-web/bim'

CSS Changes

All Tailwind utility classes (vc-flex, vc-text-sm, etc.) have been replaced with semantic CSS classes. If you were targeting vim-web's internal CSS classes in your stylesheets, they have changed. The component structure and vim- prefixed classes are stable.

Peer Dependencies

0.5 1.0-beta.1
react ^18.3.1 ^18.3.1 || ^19.0.0
react-dom ^18.3.1 ^18.3.1 || ^19.0.0

React 18.3+ continues to work. React 19 is now also supported.

1.0.0-alpha.1

10 Mar 19:36

Choose a tag to compare

Selection & Outline Improvements

Smoother Selection Outlines

Selection outlines now use Sobel convolution edge detection with bilinear texture sampling, replacing the previous Chebyshev ring approach. This produces smoother, antialiased outlines with natural soft falloff at the edges.

The outline shader supports a scale uniform so that outline thickness remains consistent in screen pixels regardless of the render target resolution.

Selection Overlay Modes

New selection fill modes that go beyond simple outlines:

  • None — Outline only (default)
  • Default — Tint selected meshes directly in the main render pass (zero extra cost)
  • X-Ray — Renders selected elements on top of everything with a semi-transparent tint
  • See-Through — Renders a ghost of selected elements where they are behind other geometry

Overlay opacity is adjustable (0–1). Both X-Ray and See-Through render directly into the scene target, preserving the existing depth buffer from the main render pass.

Render Settings Panel

The Render Settings panel (accessible from the control bar) now includes:

Setting Type Range Default
Transparency Toggle On
Show Ghost Toggle Off
Ghost Opacity Slider 0–1
Selection Outline Toggle On
Outline Quality Select Low / Medium / High High
Outline Thickness Number 1–5 3
Selection Fill Select None / Default / X-Ray / See-Through None
Selection Opacity Slider 0–1 0.25

Outline Quality controls the render target resolution for the outline pipeline:

  • Low (0.5x) — Fastest, softer outlines
  • Medium (1x) — Balanced
  • High (2x) — Sharpest outlines, 4x more pixels to process

All settings are available programmatically via viewer.isolation:

viewer.isolation.outlineQuality.set('high')
viewer.isolation.outlineThickness.set(4)
viewer.isolation.selectionFillMode.set('xray')
viewer.isolation.selectionOverlayOpacity.set(0.3)

Performance

GPU Picker Scissor Optimization

The GPU picker now uses a 1x1 pixel scissor rect when picking, instead of rendering the full scene to the pick buffer. The GPU skips fragment processing for all pixels outside the scissor region and can cull geometry that doesn't intersect it. This significantly reduces the cost of each pick operation.

Dependencies

  • Three.js updated from 0.171 to 0.183
  • @types/three updated to 0.183.0
  • Migrated THREE.Clock to THREE.Timer (breaking change in r183)

1.0.0-alpha.0

10 Mar 19:05
ffb082f

Choose a tag to compare

This branch is a major architectural overhaul preparing vim-web for the 1.0 release. It covers five broad areas: a new public API surface, a complete outline rendering rewrite, a GPU picking system, geometry loading performance, and a thorough dead code purge.


Public API & Exports

  • ViewerApi abstraction: Both WebGL and Ultra viewers now expose a unified ViewerApi handle (WebglViewerApi / UltraViewerApi) through VIM.React.Webgl.createViewer() and VIM.React.Ultra.createViewer(). Direct class access is no longer needed for any common use case.
  • Interface-driven: Core types are now backed by I-prefixed interfaces (IVim, ICamera, ISelectable, IMarker, IMaterials, etc.). Concrete classes are @internal.
  • Tighter barrel files: Internal modules are no longer leaked through re-exports. The public surface is intentionally narrow.
  • Unique class names: Renamed internal classes for cleaner API bundles and better TypeScript declaration output.
  • viewer.core.settings removed: Settings are consumed at construction time only — exposing them as a field was misleading. Removed from IWebglViewer.
  • Material API cleanup: IMaterials now only exposes user-facing properties (ghostOpacity, ghostColor, outlineOpacity, outlineThickness, outlineColor, clippingPlanes). Internal system materials are hidden behind a system getter.
  • Element3D interface: IElement3D exposes only BIM-facing properties; mesh internals are hidden.
  • Input API: Inputs organized under viewer.core.inputs with typed PointerMode enum, configurable key handlers, and clean mouse/touch callbacks. Removed spacebar bindings.
  • Camera API: Fluent snap() / lerp(duration) API for instant vs animated camera moves. Unified frame(), orbit(), orbitTowards(), zoomTo(). Removed lookAt parameter. Rotation axes clarified (x = horizontal/yaw, y = vertical/pitch).
  • Framing renamed: viewer.react.cameraviewer.framing for clarity.
  • Signal interfaces: onXxx event properties typed as read-only signal interfaces, not mutable dispatchers.
  • Ultra API tightened: Ultra viewer API aligned with WebGL — matching fields (container, isolation, sectionBox, etc.), control bar customization via hook param, no leaked RPC internals.

GPU Picking (WebGL)

Replaced CPU raycasting as the primary picking method with a GPU-based approach:

  • Float32 render target stores packed element ID (vimIndex << 24 | elementIndex), depth, and surface normals per fragment.
  • packPickingId() / unpackPickingId() utilities pre-pack IDs at mesh build time — zero overhead per frame.
  • Markers support GPU picking (packedId attribute with MARKER_VIM_INDEX sentinel).
  • GpuPicker reads a 1×1 region on click, resolves vim + element in one readback.
  • CPU raycaster (raycaster.ts) retained as fallback.

Outline Rendering Rewrite

The outline effect was completely rewritten from depth-based to mask-based silhouette detection:

Pipeline: Scene (MSAA) → Selection Mask → Outline Edge Detect → Merge → Screen

  • Mask-based: Selected objects render with a flat white maskMaterial to a dedicated render target. Edge detection runs on the mask, not the depth buffer — eliminates depth precision artifacts at long range.
  • scene.background fix: Background color was leaking into the mask buffer and breaking edge detection. Background is now nulled during the outline composer render and restored after.
  • Configurable thickness: New thickness uniform (range 1–5) controls how many Chebyshev ring levels are sampled per fragment. Higher values = thicker outlines at a proportional sampling cost.
  • Full grid (Chebyshev ring) sampling: Replaced 8-point star sampling with a full NxN grid ring. Eliminates diagonal artifacts from the star pattern.
  • Opacity and color: outlineOpacity (0–1) and outlineColor exposed on IMaterials. Both live on the merge pass for clean separation.
  • Dead properties removed: camera, depthBuffer, color, precision and associated uniforms removed from OutlineMaterial. OutlinePass no longer receives or wires a camera.

Material System Cleanup

  • StandardMaterial removed: _opaque / _transparent StandardMaterial fields deleted from Materials. VIM meshes have always used ModelMaterial (custom GLSL3 shader) — StandardMaterial was never in the rendering path.
  • Dead settings removed:
    • skybox, skylight, sunlights — defined, parsed, never consumed
    • useFastMaterials, materials.standard.color — toggle with no effect
    • materials.section.strokeWidth/Falloff/Color — only applied to StandardMaterial shader, which was unused
  • modelColor, sectionStroke* removed from IMaterials — dead wiring to removed materials.
  • MaterialSettings now contains only ghost and outline.
  • MaterialSet: New value type { opaque, transparent, hidden } for per-mesh material assignment. applyMaterial() helper is the single place that calls MaterialSet.get().

Geometry Loading & Performance

  • Color palette texture: Per-element colors stored in a shared 128×128 DataTexture (25³ = 15,625 quantized colors). ModelMaterial reads colors via texelFetch — no per-vertex color upload on color changes.
  • texelFetch / WebGL2: Replaced texture2D with texelFetch in shaders for direct texel access.
  • G3dSubset and offsets: Introduced G3dSubset as a filtered view of G3d instances. G3dMeshOffsets pre-computes vertex/index counts per mesh for buffer allocation.
  • InsertableGeometry chunking: Merged mesh geometry split at 16M indices to stay within buffer limits.
  • InstancedMeshFactory: Instanced meshes (>5 instances) built with per-instance packedId and ignore attributes pre-packed at build time.
  • Faster element mapping, bounding boxes, and array lookups: Hot paths replaced with typed array maps.
  • Removed vimx: Legacy vimx loading code removed.
  • No empty meshes: Meshes with zero instances are no longer created.

Camera & Controls

  • Orbit target on select: Orbit target snaps to selected element center.
  • Zoom resets orbit target: Scroll-to-zoom updates the orbit target to the cursor hit point.
  • Floating target fix: Orbit target no longer drifts after camera reset.
  • Touch: Pinch and pan gestures both fire correctly. Faster scroll.
  • lockMovement / lockRotation: Per-axis movement and rotation locks on ViewerSettings.camera.
  • Delta time: Fixed camera animation delta time calculation.

Ultra Viewer Updates

  • Color overrides: Ultra viewer supports element.color = new RGBA32(...) overrides, aligned with WebGL API.
  • nodeStatestate: Renamed for clarity. element.state = VisibilityState.GHOSTED (enum: VISIBLE, HIDDEN, GHOSTED, HIGHLIGHTED).
  • Remove overrides: Ultra viewer supports removing overrides, matching WebGL.
  • Error messages: Improved error/status display. Errors not minimized by default.
  • Ultra 6.0.0 RPC: Updated RPC client to match Ultra 6 protocol.

Gizmos

  • Marker GPU picking: Markers register packedId attribute for GPU picker hit detection.
  • Orbit gizmo: Camera gizmo rebuilt to match Ultra's visual style. Uses sphere coordinates.
  • Section box / axes cleanup: Gizmo classes tightened, internals hidden behind IGizmo* interfaces.

Developer Experience

  • CLAUDE.md: Comprehensive architecture documentation. Covers loading pipeline, rendering pipeline, GPU picker, mesh type hierarchy, React patterns, and camera API.
  • INPUT.md: Dedicated input system documentation.
  • @internal tags: System-only classes and methods marked throughout.
  • TypeDoc comments: Cleaned up and expanded across public API.

Breaking Changes

  • viewer.core.settings removed from IWebglViewer
  • StandardMaterial, modelColor, sectionStroke* removed from IMaterials
  • MaterialSettings.useFastMaterials, .standard, .section removed
  • skybox, skylight, sunlights removed from ViewerSettings
  • viewer.react.camera renamed to viewer.framing
  • nodeState renamed to state (Ultra); use VisibilityState enum
  • Input key binding API changed — register via inputs.keyboard.registerKeyDown()
  • Camera lookAt parameter removed — use orbitTowards() or set(position, target)

Ultra Auth Token

15 Jan 21:22
b974b77

Choose a tag to compare

Ultra Version: 5.0.0

Webgl

  • Updated skybox color
  • Fixed bug with section box face highlight when mouse leaving canvas

Ultra

  • Implemented support for files with auth tokens

React

  • Improved logger to show caller info

Various bugfixes

14 Jan 19:32
63b82a8

Choose a tag to compare

**WebG

  • Fixed bug where the tooltip text was getting cut at the bottom
  • The orbit ball gizmo no longer appears in first person mode
  • Updated error messages and fixed typos
  • Fixed a bug where outline wasn't correctly displayed when the section box was active

Ultra

  • Updated ghost color to match desktop viewer

0.3.39

10 Jan 16:26
e4dc798

Choose a tag to compare

ULTRA requires Server 5.0.0

Webgl

  • Updated threejs to latest version 0.171.0
  • Updated all dependencies to recent versions
  • Meshes with few instances are now merged along the unique meshes increasing performance
  • Unique merged mesh is now chunked into chunks of 4M vertices
  • Skybox material no longer writes to depth
  • Changed base material from Phong to Lambert
  • Removed the custom AA pass when camera was idle
  • Updated rendering pipeline to use default Web2 render target AA

Migration Note:
The new threejs light model uses PI as the default value.

React

  • Fixed a bug in error message where clicking the link would not open a new tab.
  • Message box is now reactive to the scale of the app
  • Updated the loading box to display if it is loading in webgl or ultra mode.

Ultra

  • Updated client to match server 5.0.0
  • Client will now disconnect and show an error message if no streams are available on the server
  • Fixed a bug which caused flickering of the progress bar
  • Removed mechanism where messages sent before calling connect would be sent after. (You can now await Connect())

Others
-Updated cdn urls to storage.cdn.vimaec.com

Package

  • Made the output css file be called style.css

Initial vim-web release

09 Dec 21:18

Choose a tag to compare

0.3.27

Build website[ci skip]