Skip to content

Nuclideon/EsriIntegration

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

Nuclideon udSDK for the ArcGIS Maps SDK for JavaScript

Drop-in integration for Nuclideon's udSDK — render UDS point clouds inside an ArcGIS <arcgis-scene> with depth correctly interleaving against the ArcGIS-rendered basemap, terrain, and 3D scene layers. The bridge hooks into the ArcGIS managed render pipeline via a RenderNode, so udSDK composites as just another stage of the SceneView's frame rather than as a detached overlay.

Language:              Javascript / HTML
Type:                  Integration
Contributor:           Nuclideon Development Team <info@nuclideon.com>
Organization:          Nuclideon, https://nuclideon.com
Date:                  2026-06-16
ArcGIS Versions:       Maps SDK for JavaScript 5.x (ESM build)
udSDK Version:         2.6.1

Quick start

<script type="module" src="https://js.arcgis.com/5.0/"></script>
<script src="https://nuclideon.com/cdn/integrations/esri/1.0.0/udsdk-arcgis.js"></script>

<arcgis-scene id="scene" basemap="hybrid" ground="world-topobathymetry"
              viewing-mode="global" style="width:100%;height:100vh"></arcgis-scene>
<script>
  udSDKArcGIS.attach(document.getElementById("scene"), {
    clientName: "Acme Portal",
    models: ["https://my-bucket.s3.amazonaws.com/site.uds"],
  });
</script>

A worked example lives in index.html.

Requirements

  • The ArcGIS Maps SDK for JavaScript 5.x on the page as the <script type="module" src="https://js.arcgis.com/5.0/"> ESM build. attach() polls for the $arcgis global, so the script tags can sit in the obvious order even though the module script is implicitly deferred.
  • Host page must be cross-origin isolated — udSDK is a threaded emscripten build and needs SharedArrayBuffer. Set these on the page response:
    Cross-Origin-Opener-Policy: same-origin
    Cross-Origin-Embedder-Policy: require-corp    (or credentialless)
    
    Verify at runtime: window.crossOriginIsolated === true.
  • The CDN serving the udSDK siblings (udSDKjs.js, udSDKjs.wasm, easyudSDKjs.js) must send Access-Control-Allow-Origin and Content-Type: application/wasm on the .wasm. Under COEP: require-corp it must also send Cross-Origin-Resource-Policy: cross-origin on those files, and your .uds hosts must do the same.
  • A Nuclideon udCloud account to sign in.

API

udSDKArcGIS.attach(sceneEl, opts) returns an EventTarget controller. sceneEl is the <arcgis-scene> element.

Options

Option Default Notes
clientName "arcgis-<hostname>" OAuth consent app name
models [] array of url strings or {url, resolution, slot}
signInUI "auto" "auto" shows the built-in box; false to BYO
signInLabel "Sign in to udCloud" button text
autoEnable true attach the RenderNode (make udSDK visible) immediately
tryDomainLogin "auto" try silent SSO before falling back to OAuth popup
serverAddress (default udCloud) override for staging / self-hosted / regional
baseUrl pinned SDK CDN base where to fetch the udSDKjs.* siblings
arcgisTimeoutMs 30000 how long to wait for $arcgis to appear
onStatus null emscripten loader status callback

Controller

  • signIn()Promise. Must be triggered from a user gesture.
  • loadModel(spec)Promise<handle>. spec is a url string or {url, resolution, slot} (resolution default 2.5, slot default -1).
  • enabled — show/hide udSDK by attaching/detaching the RenderNode.
  • signedIn, view, renderNode.
  • destroy() — remove the RenderNode + UI.

Events

Event detail
ready
signed-in { method: "oauth" | "domain" }
model-loaded { url, handle }
model-error { url, code, error }
sign-in-error { code, error }

Local development

A tiny static server is included that issues the required COOP/COEP headers so the demo runs locally without setting up nginx/Caddy/etc.:

python httpserver.py
# http://localhost:8080/index.html

How it works

  1. Bootstrap. udSDK is a threaded emscripten build, which means three non-obvious things have to happen when loading it cross-origin:

    • Module.locateFile points emscripten at the CDN base so it fetches udSDKjs.wasm from there instead of the page's origin.
    • The pthread pool spawns workers via new Worker(scriptUrl), which browsers refuse for cross-origin URLs regardless of CORS. The wrapper fetches udSDKjs.js as text, wraps it in a Blob, and hands the resulting same-origin Blob URL to emscripten via Module.mainScriptUrlOrBlob. easyudSDKjs.js stays a regular cross-origin <script> since it spawns no workers.
    • The page has to be cross-origin isolated (see Requirements) so SharedArrayBuffer is exposed. The wrapper checks crossOriginIsolated up front and fails loudly if it's false.
  2. Sign-in. Tries udSDKJS_CreateSharedFrom_udCloud(name, null) first — a silent domain auth that succeeds if the browser already has a session with the configured udCloud server (typically via corporate SSO). If that fails, the built-in sign-in box opens an OAuth popup from a user gesture and finishes via udSDKJS_ConnectStart + udSDKJS_ConnectComplete.

  3. The RenderNode. Rather than overlaying a separate canvas, the bridge subclasses ArcGIS's RenderNode and inserts itself into the SceneView's managed render pipeline. It declares consumes: { required: ["composite-color"] } and produces: "composite-color" — so ArcGIS hands it the fully composited scene color (and its depth-stencil attachment) and takes back the node's output as the new composite. Toggling enabled flips produces between "composite-color" and null, which detaches the node from the pipeline.

  4. Per-frame render. Each frame the node's render(inputs) runs two screen-space passes into the output framebuffer (a full-screen triangle, no geometry):

    • It first re-attaches the input's depth-stencil to the output so udSDK fragments depth-test against everything ArcGIS already drew.
    • Pass 1 blits the incoming composite-color straight through, so the ArcGIS scene is preserved.
    • Pass 2 (only once udSDK is ready) resizes udSDK's offscreen scene if the viewport changed, pushes the camera's viewMatrix and projectionMatrix into udSDK via udSDKJS_SetMatrix, calls udSDKJS_RenderQueue(), then copies udSDK's colour and depth buffers into two GL textures and draws them. The fragment shader writes gl_FragDepth from the udSDK depth sample so udSDK fragments interleave correctly with the ArcGIS depth buffer.
    • The node calls requestRender() every frame so udSDK's streaming/LOD keeps progressing even when the camera is still.
  5. Colour buffer details. udSDK delivers colour as BGRA, so the shader swizzles col.bgr on output. The wrapper also tags the buffer's top-left pixel magenta before upload; the shader checks that pixel to detect whether udSDK delivered the frame vertically flipped and flips the sample UV to compensate.

  6. Depth buffer. udSDK's depth comes back as float32, uploaded directly into an R32F texture and sampled as-is, then remapped into clip range (depth * 0.5 + 0.5) when written to gl_FragDepth.

Limitations

  • Single-instance only. udSDK's render state is process-global, so one attach() per page.
  • No WebGL context-loss recovery. Colour/depth textures aren't recreated after a lost context. Reload the page.
  • WebGL2 / R32F required. The shaders are GLSL 3.00 ES and the depth path relies on a renderable/sampleable R32F texture. The ArcGIS Maps SDK 5.x runs WebGL2, so this holds in practice.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Contributors