npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

beckhoff-xts-viewer-3d

v6.2.0

Published

Unofficial, independent React component for rendering Beckhoff XTS linear-motor systems in 3D using Three.js. Not a Beckhoff product and not affiliated with or endorsed by Beckhoff Automation GmbH & Co. KG.

Readme

⚠️ Disclaimer — this is not a Beckhoff product

beckhoff-xts-viewer-3d is an independent, unofficial open-source project. It is not developed, published, reviewed, endorsed, sponsored or supported by Beckhoff Automation GmbH & Co. KG or by HepcoMotion, and it has no affiliation with either company. Please do not contact their support about it — open an issue instead.

"Beckhoff", "XTS" and "TwinCAT" are trademarks of Beckhoff Automation GmbH & Co. KG; "Hepco", "HepcoMotion" and "GFX" are trademarks of Hepco Slide Systems Ltd. They are used here only descriptively, to identify the hardware this viewer renders, and remain the property of their respective owners.

The 3D geometry is derived from CAD data published by those manufacturers for engineering use. Rights to that data and to the product designs it depicts stay with their owners: the MIT license covers this project's own source code only and grants no rights to third-party CAD data, trademarks or other intellectual property. Rights holders can reach the maintainer through a GitHub issue, and any material will be removed on request.

The software is provided "as is", without warranty of any kind (see LICENSE). It is a visualization aid: not a safety device, not validated for machine control or any safety-related function, and no substitute for the manufacturer's own documentation.

beckhoff-xts-viewer-3d

npm npm assets License: MIT CI

A React component that renders Beckhoff XTS linear-motor systems — and Hepco GFX rail variants — in 3D. It takes a declarative description of modules, movers and tools and handles the path math, GLB loading, mover animation, selection, lighting and camera work.

It covers the same ground as the official 2D Beckhoff.TwinCAT.HMI.XTS.Controls viewer, using real CAD geometry in three dimensions.

A 5 m XTS packaging line rendered by the viewer

Installation

npm install beckhoff-xts-viewer-3d
npm install react react-dom three

| Requirement | Version | Why | | ------------------------------------------------ | ------------------------ | -------------------------------------------------- | | react / react-dom | ^19.0.0 | required by @react-three/fiber 9 | | three | >= 0.181.0 | the viewer uses the console-hook API added in r181 | | @react-three/fiber | >= 9.0.0 | | | @react-three/drei | >= 10.0.0 | | | three-stdlib | >= 2.36.0 | GLTF, KTX2 and Meshopt loaders | | postprocessing + @react-three/postprocessing | >= 6.39.2 / >= 3.0.0 | optional — only needed for SSAO and bloom | | Node | >= 20 | build tooling only; the runtime is browser ESM |

The package is "type": "module" and ships ESM and CJS from ./dist/index.{js,cjs,d.ts}. sideEffects: false, so unused exports tree-shake out.

Any modern bundler works (Vite, Webpack, Next.js, Remix, Astro). If your bundler installs more than one copy of three, deduplicate it — see Troubleshooting.

Minimal example

import { XtsViewer3D } from 'beckhoff-xts-viewer-3d';

<XtsViewer3D
  config={{
    processingUnits: [
      {
        objectId: 0,
        moverType: 'AT9014_0055',
        parts: [
          {
            objectId: 0,
            globalNumber: 0,
            modules: [
              { moduleType: 'AT2001_0250', globalNumber: 1 },
              { moduleType: 'AT2000_0250', globalNumber: 2 },
              { moduleType: 'AT2050_0500', globalNumber: 3 },
              { moduleType: 'AT2050_0501', globalNumber: 4 },
              { moduleType: 'AT2001_0250', globalNumber: 5 },
              { moduleType: 'AT2000_0250', globalNumber: 6 },
              { moduleType: 'AT2050_0500', globalNumber: 7 },
              { moduleType: 'AT2050_0501', globalNumber: 8 },
            ],
          },
        ],
        movers: [{ index: 0, id: 0, partOid: 0, partPositionMm: 200 }],
      },
    ],
  }}
/>;

No asset hosting is required. GLBs stream from the matching beckhoff-xts-viewer-3d-assets release on jsDelivr; see asset hosting to self-host them instead.

Module catalogue

Every image on this page comes out of the component itself, through the same exportScreenshot() a consumer calls, and shows a layout a line would actually be built as — a 5 m racetrack with four stations, a buffer loop beside it. See docs/screenshots for the capture script and playground/src/configs.ts for the layouts themselves.

| | | | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Standard ATStandard AT — AT2001 infeed, AT2000 straights and the AT2050 180° clothoid reversal. | Eco AT2200Eco AT2200 / AT2202 — 500 mm straights, which pair naturally with the 500 mm reversal. | NCT with AT8200 toolsNCT AT2002 / AT2102 — high modules carrying AT8200 tool carriers on the movers. | | Hygienic ATHHygienic ATH — stainless housings, sealed joints and the ATH9011 mover. | Hepco GFX2Hepco GFX2 — the procedural GFX rail profile with a GFX2 1TC carriage instead of the Beckhoff guiding rail. | Material close-upReal materials, not CAD colours — anodised housing, stator packs, printed type plate with its LED row. |

The GLBs ship with a named PBR material library rather than the CAD sources' placeholder colours — see Asset pipeline.

Features

Geometry and layout. The full Beckhoff module and mover catalogue — Standard AT, Eco AT2200, NCT (AT2002 / AT2102 with AT8200 tools), Hygienic ATH and Hepco GFX2 — with straights, ±22.5° and ±45° curves and the AT2050 / ATH2050 180° clothoid reversal. Both Hepco guideways are modelled as procedural sections swept along the track and picked by the carriage on it: the TL1 1-Trak spear bar under a 1TC carriage, the PRT2 size-44 track under an FCC one. Module-to-module C0/C1 continuity is pinned by golden fixtures. Per-XPU trackTransform places independent lines in one scene, and positionFrame remaps every position value into the host's coordinate convention without touching the rest of the config.

Mover motion. setMoverPositions() writes into a per-component store that useFrame drains directly into the three.js scene graph, so a 60 Hz drive loop produces no React renders. An instanced fast path batches mover bodies into a draw-call count that no longer grows with the mover count, where per-mover scene nodes are not needed.

Rendering. ACES filmic tone mapping, image-based lighting from a procedurally built indoor environment, anisotropic filtering and optional PCF-soft shadows, all switchable through display.*. SSAO and bloom are available when the optional post-processing peers are installed.

Interaction and status. Click selection for modules, movers, whole tracks and static custom assets, tinting the GLB itself rather than overlaying wireframes; draggable translate / rotate / scale handles on a selected track or custom asset, in the same palette as the orientation gizmo; drive-status blink plus camera-facing warning and error icons; feed-segment (Einspeisestrang) tinting that wraps the seam of a closed loop; stations, areas, dimensions and info bars; stop-position ghost movers; and a stator heatmap driven by (positionMm, value) samples.

Measuring and annotating. CAD-style tools — point-to-point distance with optional ΔX/ΔY/ΔZ guides, angle, polyline, and distance along the XTS path — picked in the scene with snapping to geometry corners and edges as well as to mover centres, module boundaries, station stops and the track path itself. Annotations pin a label anywhere, including to a mover, where they follow it while it drives. Everything works the same in the 2D plan view, renders into screenshots and video frames, and is fully drivable from viewerRef.current.measurements.

Analysis. Sub-millimetre mover collision detection, as a one-shot call or a continuous monitor, plus module-level collision probes.

Export. exportScreenshot() renders offscreen at any resolution with MSAA, in current-camera, top-down or saved-camera mode. beginFrameCapture() opens a reusable session whose grab() returns a frame synchronously without image encoding, and keeps producing frames while the window is minimised. Both bypass the post-processing chain; the result reports whether that happened.

Camera. Orthographic top-down projection for a live 2D plan view, an animated focusOn() for stations, areas, movers, modules or the whole scene, and an opt-in X / Y / Z orientation gizmo.

Measurements and annotations

const viewer = useRef<XtsViewer3DRef>(null);
const [tool, setTool] = useState<MeasurementTool>('none');

<XtsViewer3D
  ref={viewer}
  config={config}
  // The same tools work in the 3D view and the 2D plan view.
  projection={plan2D ? 'orthographic' : 'perspective'}
  measurement={{
    tool, // 'distance' | 'angle' | 'path' | 'trackDistance' | 'annotation'
    snap: { enabled: true, radiusPx: 14 },
    onMeasurementCreate: (m, result) => console.log(m.kind, result.text),
  }}
/>;

// …or place and read measurements without any user interaction:
viewer.current.measurements.add({
  kind: 'distance',
  points: [{ positionMm: [0, 0, 200] }, { positionMm: [1000, 0, 200] }],
});
viewer.current.measurements.results(); // [{ value: 1000, text: '1 000.0 mm', … }]
const saved = viewer.current.measurements.toJSON(); // persist, restore with fromJSON()

See Measurements + annotations for the tools, the snap kinds and the full API.

Gallery

| | | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Two parallel linesA packaging line and a buffer loop side by side, placed with trackTransform. | Stations and areasStation tubes with their stop markers, ghost movers parked on the stops, and cleanroom / manual-access zones. | | Dimensions and stationsDimensions along the track, stepped out from the modules they measure. | Stator heatmapVertex-colour gradient along the centerline, fed from (positionMm, value) samples. | | Collision detectionTwo movers of the line parked at a 1 mm overlap — checkMoverCollisions() reports the penetration. | Drive statusEmissive tint on the GLB plus camera-facing warning and error icons, on modules and movers alike. | | Feed segmentsfeedSegmentHighlights tints whole electrical strands; the pink one wraps the loop seam. | Measurements and annotationsA distance across the loop with ΔX/ΔY guides and two annotations, placed through viewerRef.current.measurements. | | SelectionSelection tints the GLB itself — two modules green, one mover orange — rather than overlaying a wireframe. | Shadows and IBLOpt-in PCF-soft shadows over the procedurally built indoor environment. | | Many movers750 movers on three ovals, animated at 60 Hz with no React commits in steady state. | |

Top-down export

exportScreenshot({ mode: 'top-down' }) — orthographic, fitted to the scene AABB. The same view is available live through projection="orthographic".

Troubleshooting

Modules render as yellow boxes and movers as blue boxes

The viewer is showing wireframe placeholders because no GLB was accepted. The console also reports THREE.WARNING: Multiple instances of Three.js being imported, and no models/*.glb requests appear in the network panel.

This happens when a transitive dependency pins its own copy of three. Two copies mean two THREE.* namespaces, and the instanceof checks inside useGLTF reject every parsed scene across that boundary.

Deduplicate three in your bundler:

// vite.config.ts
export default defineConfig({
  plugins: [react()],
  resolve: { dedupe: ['three'] },
});

For Webpack and Next.js, alias three to your root node_modules/three. Bundler configuration has the full snippets and explains how to clear Vite's pre-bundle cache afterwards.

Documentation

  • Using the component — every prop, every ref method, asset hosting, recipes and performance tuning.
  • Adding a module — taking a new module, mover or tool type from STP file to calibrated GLB.
  • Performance — the asset compression pipeline and the runtime budget.
  • Releasing — the automated publish flow.
  • Migrating to v6 — what changed and what to do about it.

Contributing

Setup, the asset pipeline, the repository layout and the release flow are in CONTRIBUTING.md.

License

MIT — see LICENSE.