{"id":75,"date":"2026-04-22T12:32:16","date_gmt":"2026-04-22T12:32:16","guid":{"rendered":"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/?page_id=75"},"modified":"2026-08-11T12:11:32","modified_gmt":"2026-08-11T12:11:32","slug":"portfolio","status":"publish","type":"page","link":"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/portfolio\/","title":{"rendered":"Portfolio"},"content":{"rendered":"\n<div class=\"vf-grid | vf-grid__col-4\"><div class=\"vf-grid__col--span-4\"><!--[vf\/content]-->\n<div class=\"vf-content\">\n\n<div class=\"vf-grid | vf-grid__col-3\"><div class=\"vf-grid__col--span-2\"><!--[vf\/content]-->\n<div class=\"vf-content\">\n\n<p>Our portfolio offers insight into the variety of instruments and hardware we have produced in recent years. We design and build a mix of modular components that can be reused across projects, and highly-specific custom parts.<\/p>\n\n\n\n<p>A number of our systems have been deployed at research institutions across Europe (see map right), and can be ordered or customized on request. To request one of our instruments, <a href=\"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/contact\/\" data-type=\"page\" data-id=\"161\">contact us<\/a>.<\/p>\n\n\n\n<p>Scroll down to browse and search our portfolio. <\/p>\n\n<\/div>\n<\/div>\n\n\n<div><!--[vf\/content]-->\n<div class=\"vf-content\">\n\n<h5 class=\"wp-block-heading\">Where&#8217;s our hardware in use?<\/h5>\n\n\n\n<!-- MapLibre GL JS -->\n<link href=\"https:\/\/unpkg.com\/maplibre-gl@5.6.2\/dist\/maplibre-gl.css\" rel=\"stylesheet\">\n\n<style>\n.siw-map-wrapper {\n    width: 100%;\n    max-width: 100%;\n    margin: 1rem 0;\n    overflow: hidden;\n    box-sizing: border-box;\n}\n\n#siw-deployment-map {\n    width: 100%;\n    aspect-ratio: 1 \/ 1;\n    min-height: 250px;\n    max-height: 500px;\n\n    border: 1px solid #d6dde5;\n    border-radius: 8px;\n    overflow: hidden;\n    background: #f8fafb;\n}\n<\/style>\n\n<div class=\"siw-map-wrapper\">\n    <div id=\"siw-deployment-map\"><\/div>\n<\/div>\n\n<script src=\"https:\/\/unpkg.com\/maplibre-gl@5.6.2\/dist\/maplibre-gl.js\"><\/script>\n\n<script>\nconst deployments = [\n    { city: \"Heidelberg\",        lat: 49.3988, lon:  8.6724 },\n    { city: \"Hamburg\",           lat: 53.5511, lon:  9.9937 },\n    { city: \"Brussels\",          lat: 50.8503, lon:  4.3517 },\n    { city: \"T\u00fcbingen\",          lat: 48.5216, lon:  9.0576 },\n    { city: \"Grenoble\",          lat: 45.1885, lon:  5.7245 },\n    { city: \"Vienna\",            lat: 48.2082, lon: 16.3738 },\n    { city: \"Rome\",              lat: 41.9028, lon: 12.4964 },\n    { city: \"Barcelona\",         lat: 41.3874, lon:  2.1686 },\n    { city: \"Athens\",            lat: 37.9838, lon: 23.7275 },\n    { city: \"Thessaloniki\",      lat: 40.6401, lon: 22.9444 },\n    { city: \"Lisbon\",            lat: 38.7223, lon: -9.1393 },\n    { city: \"Milan\",             lat: 45.4642, lon:  9.1900 },\n    { city: \"Utrecht\",           lat: 52.0907, lon:  5.1214 },\n    { city: \"Munich\",            lat: 48.1372, lon: 11.5756 },\n    { city: \"Prague\",            lat: 50.0755, lon: 14.4378 },\n    { city: \"Esch-sur-Alzette\",  lat: 49.4958, lon:  5.9806 },\n    { city: \"Budapest\",          lat: 47.4979, lon: 19.0402 },\n    { city: \"Dortmund\",          lat: 51.5136, lon:  7.4653 },\n    { city: \"Cambridge\",         lat: 52.2053, lon:  0.1218 },\n    { city: \"Brno\",              lat: 49.1951, lon: 16.6068 },\n    { city: \"Jena\",              lat: 50.9271, lon: 11.5892 },\n    { city: \"Lausanne\",          lat: 46.5218, lon:  6.6333 },\n];\n\nconst map = new maplibregl.Map({\n    container: \"siw-deployment-map\",\n\n    \/\/ OpenFreeMap style\n    style: \"https:\/\/tiles.openfreemap.org\/styles\/positron\",\n\n    center: [8.6724, 49.3988],\n    zoom: 2.7,\n\n    attributionControl: false,\n\n    dragRotate: false,\n    pitchWithRotate: false,\n\n    scrollZoom: false,\n    doubleClickZoom: false,\n    touchZoomRotate: false,\n    boxZoom: false,\n    keyboard: false\n});\n\nmap.addControl(\n    new maplibregl.NavigationControl({\n        showCompass: false\n    }),\n    \"top-right\"\n);\n\nmap.on(\"load\", () => {\n\n    \/\/\n    \/\/ Hide state\/province boundaries\n    \/\/\n    \/\/ The exact layer names may evolve as OpenFreeMap updates its\n    \/\/ style, so this is written defensively.\n    \/\/\n\n    map.getStyle().layers.forEach(layer => {\n\n        const id = layer.id.toLowerCase();\n\n        if (\n            id.includes(\"admin\") &&\n            (\n                id.includes(\"state\") ||\n                id.includes(\"province\") ||\n                id.includes(\"admin-1\") ||\n                id.includes(\"adm1\")\n            )\n        ) {\n            map.setLayoutProperty(layer.id, \"visibility\", \"none\");\n        }\n\n    });\n\n    \/\/\n    \/\/ Add deployment markers\n    \/\/\n\n    deployments.forEach(site => {\n\n    const marker = document.createElement(\"div\");\n\n    marker.innerHTML = `\n<svg width=\"18\" height=\"24\" viewBox=\"0 0 22 30\"\n     xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n    <defs>\n        <filter id=\"shadow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n            <feDropShadow dx=\"0\" dy=\"1.5\" stdDeviation=\"1.5\"\n                          flood-color=\"#000000\"\n                          flood-opacity=\"0.25\"\/>\n        <\/filter>\n    <\/defs>\n\n    <g filter=\"url(#shadow)\">\n        <path\n            d=\"M11 1\n               C5.5 1 1 5.5 1 11\n               C1 18.5 11 29 11 29\n               C11 29 21 18.5 21 11\n               C21 5.5 16.5 1 11 1Z\"\n            fill=\"#3AA655\"\n            stroke=\"white\"\n            stroke-width=\"2\"\/>\n\n        <circle\n            cx=\"11\"\n            cy=\"11\"\n            r=\"3.5\"\n            fill=\"white\"\/>\n    <\/g>\n<\/svg>\n`;\n\n    new maplibregl.Marker({\n        element: marker,\n        anchor: \"bottom\"\n    })\n    .setLngLat([site.lon, site.lat])\n    .addTo(map);\n\n});\n\n});\n<\/script>\n\n<\/div>\n<\/div>\n<\/div>\n\n\n\n<section class=\"vf-content siw-portfolio\" aria-labelledby=\"siw-portfolio-title\">\n  <style>\n  .siw-portfolio {\n  --siw-accent: #00528a;\n  --siw-accent-2: #2878b7;\n  --siw-border: #d6dde5;\n  --siw-surface: #ffffff;\n  --siw-surface-alt: #f3f6f8;\n  --siw-text: #1d232a;\n  --siw-muted: #5f6b77;\n  --siw-shadow: 0 10px 24px rgba(29, 35, 42, 0.08);\n  color: var(--siw-text);\n}\n\n.siw-portfolio *,\n.siw-portfolio *::before,\n.siw-portfolio *::after {\n  box-sizing: border-box;\n}\n\n.siw-portfolio ul,\n.siw-portfolio ol {\n  list-style: none !important;\n  margin-left: 0 !important;\n  padding-left: 0 !important;\n}\n\n.siw-portfolio li {\n  list-style: none !important;\n}\n\n.siw-portfolio__intro {\n  margin-bottom: 1.5rem;\n}\n\n.siw-portfolio__controls {\n  display: grid;\n  gap: 1rem;\n  margin: 1.25rem 0 1.5rem;\n  padding: 1rem;\n  border: 1px solid var(--siw-border);\n  border-radius: 0.5rem;\n  background: var(--siw-surface-alt);\n}\n\n.siw-portfolio__search label,\n.siw-portfolio__filters h2 {\n  display: block;\n  margin: 0 0 0.5rem;\n}\n\n.siw-portfolio .siw-portfolio__filter-list {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 0.5rem;\n}\n\n.siw-portfolio__filter-list li {\n  margin-bottom: 0 !important;\n  line-height: 1 !important;\n}\n\n.siw-portfolio__filter-btn {\n  appearance: none;\n  cursor: pointer;\n  padding: 0;\n  border: 0;\n  background: transparent;\n}\n\n.siw-portfolio__filter-btn .vf-badge,\n.siw-portfolio .vf-badge--tertiary {\n  font-size: 0.75rem;\n  padding-block: 0.16rem;\n  padding-inline: 0.42rem;\n  line-height: 1;\n}\n\n.siw-portfolio .vf-card__text {\n  margin-bottom: 1.5rem !important;\n}\n\n.siw-portfolio__meta {\n  margin: 0 0 1rem;\n  color: var(--siw-muted);\n}\n\n.siw-portfolio .siw-portfolio__results {\n  display: grid;\n  grid-template-columns: repeat(4, minmax(0, 1fr));\n  width: 100%;\n  max-width: 100%;\n  gap: 1rem;\n  margin: 0;\n}\n\n@media (max-width: 40rem) {\n  .siw-portfolio .siw-portfolio__results {\n    grid-template-columns: 1fr;\n  }\n}\n\n.siw-portfolio .siw-portfolio__tags {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 0.25rem 0.35rem;\n  margin: 0;\n  padding: 0;\n  margin-top: 0;\n}\n\n.siw-portfolio .siw-portfolio__tags li {\n  margin: 0 !important;\n  line-height: 0 !important;\n}\n\n.siw-portfolio__card-link {\n  display: block;\n  height: 100%;\n  text-decoration: none;\n  color: inherit;\n}\n\n.siw-portfolio__card-link:hover,\n.siw-portfolio__card-link:focus-visible,\n.siw-portfolio__card-link:hover *,\n.siw-portfolio__card-link:focus-visible * {\n  text-decoration: none !important;\n}\n\n.siw-portfolio__link-icon {\n  position: absolute;\n  right: 1rem;\n  bottom: 1rem;\n  color: #b0b8c1;\n  font-size: 0.95rem;\n  line-height: 1;\n  transition: color 0.15s ease;\n  pointer-events: none;\n}\n\n.siw-portfolio__card-link:hover .siw-portfolio__link-icon,\n.siw-portfolio__card-link:focus-visible .siw-portfolio__link-icon {\n  color: #6b7785;\n}\n\n.siw-portfolio__card {\n  position: relative;\n}\n\n.siw-portfolio__results:hover .siw-portfolio__card {\n  opacity: 0.5;\n  transition: opacity 0.15s ease;\n}\n\n.siw-portfolio__results:hover .siw-portfolio__card:hover {\n  opacity: 1;\n}\n\n.siw-portfolio__card-link:hover,\n.siw-portfolio__card-link:focus-visible {\n  text-decoration: none !important;\n}\n\n.siw-portfolio__card-link:hover *,\n.siw-portfolio__card-link:focus-visible * {\n  text-decoration: none !important;\n}\n\n.siw-portfolio__empty {\n  padding: 1rem;\n  border: 1px dashed var(--siw-border);\n  border-radius: 0.5rem;\n  background: #fff;\n  color: var(--siw-muted);\n}\n\n  <\/style>\n  <div class=\"siw-portfolio__intro\">\n    <p class=\"vf-text\">\n      Use the category filters and search box to narrow results.\n    <\/p>\n  <\/div>\n\n  <div class=\"siw-portfolio__controls\" role=\"search\" aria-label=\"Portfolio filters\">\n    <div class=\"siw-portfolio__search\">\n      <input\n        id=\"siw-portfolio-search\"\n        name=\"siw-portfolio-search\"\n        type=\"search\"\n        placeholder=\"Search our portfolio\"\n        class=\"vf-form__input vf-form__input--filter\"\n        autocomplete=\"off\"\n      \/>\n    <\/div>\n\n    <div class=\"siw-portfolio__filters\">\n      <h2 class=\"vf-heading vf-heading--h4\">Filter by category<\/h2>\n      <ul class=\"siw-portfolio__filter-list\" id=\"siw-portfolio-filters\"><\/ul>\n    <\/div>\n\n    <div class=\"siw-portfolio__filters\">\n      <h2 class=\"vf-heading vf-heading--h4\">Filter by workshop<\/h2>\n      <ul class=\"siw-portfolio__filter-list\" id=\"siw-portfolio-workshop-filters\"><\/ul>\n    <\/div>\n  <\/div>\n\n  <p class=\"vf-text siw-portfolio__meta\" id=\"siw-portfolio-meta\" aria-live=\"polite\"><\/p>\n\n  <div class=\"vf-card-container siw-portfolio__results\" id=\"siw-portfolio-results\"><\/div>\n  <div class=\"siw-portfolio__empty\" id=\"siw-portfolio-empty\" hidden>No products match your search and filters.<\/div>\n  <script src=\"https:\/\/kit.fontawesome.com\/d367e960f6.js\" crossorigin=\"anonymous\"><\/script>\n  <script type=\"application\/json\" id=\"siw-portfolio-data\">\n    [\n      {\n        \"title\": \"Microscope Incubator\",\n        \"url\": \".\/microscope-incubator\",\n        \"summary\": \"Custom closed-loop environmental control system for advanced microscopy\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/Incubator-1-scaled.jpg\",\n        \"categories\": [\"Light Microscopy\", \"Environmental Control\", \"Standard Device\"],\n        \"workshops\": [\"Mechanical\", \"Electronics\"]\n      },\n      {\n        \"title\": \"Microliter Fluid Injector\",\n        \"url\": \"\",\n        \"summary\": \"Microfluidic pump and controller to inject fluids at rates below 1 ul\/min\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/microliter-fluid-injection.jpg\",\n        \"categories\": [\"Flow Control\",\"Microfluidics\",\"Automation\"],\n        \"workshops\": [\"Electronics\"]\n      },\n      {\n        \"title\": \"Cryo-EM Sample Shuttles\",\n        \"url\": \"\",\n        \"summary\": \"Custom shuttles for Cryo-EM grids, planchettes, and pins used in multi-stage pipelines\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/Cryo-EM-Sample-Holders1.jpeg\",\n        \"categories\": [\"Electron Microscopy\", \"Cryogenics\", \"Sample Handling\"],\n        \"workshops\": [\"Mechanical\"]\n      },\n      {\n        \"title\": \"Temperature Controller\",\n        \"url\": \"\",\n        \"summary\": \"Temperature controller for heating or coolingwith fast-switching solid state relays\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/temperature-controller.jpg\",\n        \"categories\": [\"Environmental Control\", \"Automation\"],\n        \"workshops\": [\"Electronics\"]\n      },\n        {\n        \"title\": \"Optogenetic Chamber\",\n        \"url\": \"\",\n        \"summary\": \"Enclosed light box for optogenetic activation of organisms or cells, with programmable exposure intensity &amp; patterns.\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/optogenetic-led-box-1.jpg\",\n        \"categories\": [\"Illumination\", \"Automation\", \"Timing\", \"Optogenetics\"],\n        \"workshops\": [\"Electronics\", \"Mechanical\"]\n      },\n      {\n        \"title\": \"Multichannel Chemostat\",\n        \"url\": \"\",\n        \"summary\": \"Low-flow (&lt;ul\/min) pumping and monitoring of up to 9 fluid channels, with per-channel control\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/multichannel-pump.jpg\",\n        \"categories\": [\"Flow Control\", \"Microfluidics\", \"Automation\", \"Wet Lab\"],\n        \"workshops\": [\"Electronics\"]\n    },\n      {\n        \"title\": \"Digital Gas Mixer\",\n        \"url\": \"\",\n        \"summary\": \"Digitally-controlled mixing of up to 3 gas channels, with in-line flow rate measurements\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/3ch-gas-mixer.jpg\",\n        \"categories\": [\"Environmental Control\", \"Automation\"],\n        \"workshops\": [\"Mechanical\", \"Electronics\"]\n      },\n        {\n        \"title\": \"Valve Actuator\",\n        \"url\": \"\",\n        \"summary\": \"Multi-channel valve controller with programmable timers, originally developed for cryochamber drying\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/valve-actuator.jpg\",\n        \"categories\": [\"Synchronization\", \"Timing\", \"Automation\"],\n        \"workshops\": [\"Electronics\"]\n      },\n      {\n        \"title\": \"Illumination Controllers\",\n        \"url\": \"\",\n        \"summary\": \"TTL-triggerable controllers and drivers for custom and off-the-shelf light sources\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/white-led-ring.jpg\",\n        \"categories\": [\"Illumination\", \"Synchronization\", \"Light Microscopy\", \"Automation\"],\n        \"workshops\": [\"Electronics\"]\n      },\n        {\n        \"title\": \"Digital Pulse Stretcher\",\n        \"url\": \"\",\n        \"summary\": \"Generates a programmable-width digital pulse triggered by a ns input pulse\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/digital-pulse-stretcher.png\",\n        \"categories\": [\"Automation\",\"Synchronization\", \"Timing\"],\n        \"workshops\": [\"Electronics\"]\n      },\n      {\n        \"title\": \"Analog Pulse Detector\",\n        \"url\": \"\",\n        \"summary\": \"Generate trigger signals from very fast (ns), low-amplitude (uV) pulses\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/analog-pulse-detector.png\",\n        \"categories\": [\"Automation\",\"Synchronization\",\"Timing\"],\n        \"workshops\": [\"Electronics\"]\n      },\n      {\n        \"title\": \"8-Channel 2kV Switch\",\n        \"url\": \"\",\n        \"summary\": \"High voltage switch between 8 outputs, controlled by TTL selection lines\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/8ch-hv-switch.png\",\n        \"categories\": [\"High Voltage\", \"Automation\", \"Timing\"],\n        \"workshops\": [\"Electronics\"]\n      },\n      {\n        \"title\": \"Magnetic Actuator\",\n        \"url\": \"\",\n        \"summary\": \"2D (Z\/\u0398) control of magnetic field formed by a permanent magnet array\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/magnetic-actuator.jpg\",\n        \"categories\": [\"Magnetics\", \"Actuators\", \"Light Microscopy\"],\n        \"workshops\": [\"Mechanical\", \"Electronics\"]\n      },\n      {\n        \"title\": \"Beam Position Sensor\",\n        \"url\": \"\",\n        \"summary\": \"Monitoring sensor and electronics for feedback in beam steering\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/beam-position-sensor.png\",\n        \"categories\": [\"Light Microscopy\", \"Detectors\", \"Illumination\"],\n        \"workshops\": [\"Electronics\"]\n      },\n      {\n        \"title\": \"MEMS Mirror Driver\",\n        \"url\": \"\",\n        \"summary\": \"Electronic driver for micromirror devices used for laser steering\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/mems-mirror-driver.png\",\n        \"categories\": [\"Light Microscopy\", \"Illumination\", \"Actuation\"],\n        \"workshops\": [\"Electronics\"]\n      },\n      {\n        \"title\": \"Galvo Controller\",\n        \"url\": \"\",\n        \"summary\": \"Electronic driver for laser-steering galvos used in light-sheet microscopy\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/galvo-controller-e1786048070787.png\",\n        \"categories\": [\"Light Microscopy\", \"Illumination\", \"Actuation\"],\n        \"workshops\": [\"Electronics\"]\n      },\n      {\n        \"title\": \"Tunable Lens Driver\",\n        \"url\": \"\",\n        \"summary\": \"Electronic driver for ms-switching of focal length using EL-10-30 series lenses\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/tunable-lens-driver.png\",\n        \"categories\": [\"Light Microscopy\", \"Illumination\", \"Actuation\"],\n        \"workshops\": [\"Electronics\"]\n      },\n          {\n        \"title\": \"Stacker Incubator\",\n        \"url\": \"\",\n        \"summary\": \"Large-volume environmental control system, originally designed for well-plate stackers\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/Placeholder.png\",\n        \"categories\": [\"Environmental Control\", \"Automation\", \"Standard Device\"],\n        \"workshops\": [\"Mechanical\"]\n    },\n    {\n        \"title\": \"Electrophoresis Chamber\",\n        \"url\": \"\",\n        \"summary\": \"Customizable, high-quality chambers for gel electrophoresis\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/Placeholder.png\",\n        \"categories\": [\"Wet Lab\",\"Standard Device\"],\n        \"workshops\": [\"Mechanical\"]\n    },\n    {\n        \"title\": \"Custom Optomechanics\",\n        \"url\": \"\",\n        \"summary\": \"High-precision optomechanical components for custom microscopes and detectors\",\n        \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/Placeholder.png\",\n        \"categories\": [\"Light Microscopy\"],\n        \"workshops\": [\"Mechanical\"]\n    },\n    {\n      \"title\": \"24-Channel Signal Combiner\",\n      \"url\": \"\",\n      \"summary\": \"Signal Decoupleing and conditioning for a single photon detector array (SNSPD)\",\n      \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/Placeholder.png\",\n      \"categories\": [\"Light Microscopy\", \"Detectors\", \"Signal Conditioning\"],\n      \"workshops\": [\"Electronics\"]\n    },\n    {\n      \"title\": \"Motor Controllers\",\n      \"url\": \"\",\n      \"summary\": \"Control &amp; drive boards providing multi-motor control and triggering via TTL\",\n      \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/Placeholder.png\",\n      \"categories\": [\"Automation\", \"Actuators\"],\n      \"workshops\": [\"Electronics\"]\n    },\n    {\n      \"title\": \"Data Loggers\",\n      \"url\": \"\",\n      \"summary\": \"Universal serial data logger, providing a unified and optionally remote interface to USB\/serial devices\",\n      \"image\": \"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-content\/uploads\/2026\/08\/Placeholder.png\",\n      \"categories\": [\"Data Logging\"],\n      \"workshops\": [\"Electronics\"]\n    }\n      \n    ]\n  <\/script>\n\n  <script>\n    (function () {\n      var root = document.querySelector(\".siw-portfolio\");\n      if (!root) return;\n\n      var dataEl = root.querySelector(\"#siw-portfolio-data\");\n      var resultsEl = root.querySelector(\"#siw-portfolio-results\");\n      var filtersEl = root.querySelector(\"#siw-portfolio-filters\");\n      var workshopFiltersEl = root.querySelector(\"#siw-portfolio-workshop-filters\");\n      var searchEl = root.querySelector(\"#siw-portfolio-search\");\n      var metaEl = root.querySelector(\"#siw-portfolio-meta\");\n      var emptyEl = root.querySelector(\"#siw-portfolio-empty\");\n\n      var products = JSON.parse(dataEl.textContent);\n      var state = {\n        search: \"\",\n        category: \"All\",\n        workshop: \"Any\"\n      };\n\n      var categories = [\"All\"]\n        .concat(\n          products.reduce(function (acc, product) {\n            product.categories.forEach(function (category) {\n              if (acc.indexOf(category) === -1) acc.push(category);\n            });\n            return acc;\n          }, [])\n        );\n\n      function normalize(value) {\n        return String(value || \"\").toLowerCase().trim();\n      }\n\n      function matches(product) {\n        var query = state.search;\n        var haystack = [\n          product.title,\n          product.summary,\n          product.categories.join(\" \"),\n          (product.workshops || []).join(\" \")\n        ]\n          .join(\" \")\n          .toLowerCase();\n\n        var categoryMatch = state.category === \"All\" || product.categories.indexOf(state.category) !== -1;\n        var workshopMatch = state.workshop === \"Any\" || (product.workshops || []).indexOf(state.workshop) !== -1;\n        var searchMatch = !query || haystack.indexOf(query) !== -1;\n\n        return categoryMatch && workshopMatch && searchMatch;\n      }\n\n      function renderFilters() {\n        filtersEl.innerHTML = categories\n          .map(function (category) {\n            var badgeState = category === state.category ? \"vf-badge--primary\" : \"vf-badge--secondary\";\n            return (\n              '<li><button type=\"button\" class=\"siw-portfolio__filter-btn\" data-category=\"' +\n              category.replace(\/\"\/g, \"&quot;\") +\n              '\" aria-pressed=\"' +\n              String(category === state.category) +\n              '\"><span class=\"vf-badge ' + badgeState + '\">' +\n              category +\n              \"<\/span>\" +\n              \"<\/button><\/li>\"\n            );\n          })\n          .join(\"\");\n      }\n\n      function renderWorkshopFilters() {\n        var workshopOptions = [\"Any\", \"Mechanical\", \"Electronics\"];\n\n        workshopFiltersEl.innerHTML = workshopOptions\n          .map(function (workshop) {\n            var badgeState = workshop === state.workshop ? \"vf-badge--primary\" : \"vf-badge--secondary\";\n            return (\n              '<li><button type=\"button\" class=\"siw-portfolio__filter-btn\" data-workshop=\"' +\n              workshop.replace(\/\"\/g, \"&quot;\") +\n              '\" aria-pressed=\"' +\n              String(workshop === state.workshop) +\n              '\"><span class=\"vf-badge ' + badgeState + '\">' +\n              workshop +\n              \"<\/span><\/button><\/li>\"\n            );\n          })\n          .join(\"\");\n      }\n\n      function renderResults() {\n        var filtered = products.filter(matches);\n\n        resultsEl.innerHTML = filtered\n          .map(function (product) {\n            var tags = product.categories\n              .map(function (category) {\n                return '<li><span class=\"vf-badge vf-badge--tertiary\">' + category + \"<\/span><\/li>\";\n              })\n              .join(\"\");\n\n            var hasUrl = String(product.url || \"\").trim() !== \"\";\n            var cardInner =\n              '<img decoding=\"async\" class=\"vf-card__image siw-portfolio__image\" src=\"' +\n              product.image +\n              '\" alt=\"' +\n              product.title.replace(\/\"\/g, \"&quot;\") +\n              '\">' +\n              '<div class=\"vf-card__content vf-stack vf-stack--400 siw-portfolio__card-body\">' +\n              '<h4 class=\"vf-card__heading\">' +\n              product.title +\n              \"<\/h4>\" +\n              '<p class=\"vf-card__text\">' +\n              product.summary +\n              \"<\/p>\" +\n              '<ul class=\"siw-portfolio__tags\">' +\n              tags +\n              \"<\/ul>\" +\n              \"<\/div>\";\n\n            if (hasUrl) {\n              return (\n                '<article class=\"vf-card vf-card--bordered siw-portfolio__card\">' +\n                '<a class=\"siw-portfolio__card-link\" href=\"' +\n                product.url +\n                '\">' +\n                cardInner +\n                '<span class=\"siw-portfolio__link-icon\" aria-hidden=\"true\"><i class=\"fa-solid fa-arrow-up-right-from-square\"><\/i><\/span>' +\n                \"<\/a>\" +\n                \"<\/article>\"\n              );\n            }\n\n            return '<article class=\"vf-card vf-card--bordered siw-portfolio__card\">' + cardInner + \"<\/article>\";\n          })\n          .join(\"\");\n\n        metaEl.textContent =\n          filtered.length +\n          \" product\" +\n          (filtered.length === 1 ? \"\" : \"s\") +\n          ' shown' +\n          (state.category !== \"All\" ? \" in \" + state.category : \"\") +\n          (state.workshop !== \"Any\" ? \" [\" + state.workshop + \"]\" : \"\") +\n          (state.search ? ' for \"' + state.search + '\"' : \"\");\n\n        emptyEl.hidden = filtered.length !== 0;\n      }\n\n      filtersEl.addEventListener(\"click\", function (event) {\n        var button = event.target.closest(\"button[data-category]\");\n        if (!button) return;\n\n        state.category = button.getAttribute(\"data-category\");\n        renderFilters();\n        renderResults();\n      });\n\n      workshopFiltersEl.addEventListener(\"click\", function (event) {\n        var button = event.target.closest(\"button[data-workshop]\");\n        if (!button) return;\n\n        state.workshop = button.getAttribute(\"data-workshop\");\n        renderWorkshopFilters();\n        renderResults();\n      });\n\n      searchEl.addEventListener(\"input\", function (event) {\n        state.search = normalize(event.target.value);\n        renderResults();\n      });\n\n      renderFilters();\n      renderWorkshopFilters();\n      renderResults();\n    })();\n  <\/script>\n<\/section>\n\n\n<\/div>\n<\/div>\n<\/div>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-title-left-aligned.php","meta":{"_acf_changed":false,"footnotes":""},"embl_taxonomy":[],"class_list":["post-75","page","type-page","status-publish","hentry"],"acf":[],"embl_taxonomy_terms":[],"_links":{"self":[{"href":"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-json\/wp\/v2\/pages\/75","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-json\/wp\/v2\/comments?post=75"}],"version-history":[{"count":79,"href":"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-json\/wp\/v2\/pages\/75\/revisions"}],"predecessor-version":[{"id":2987,"href":"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-json\/wp\/v2\/pages\/75\/revisions\/2987"}],"wp:attachment":[{"href":"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-json\/wp\/v2\/media?parent=75"}],"wp:term":[{"taxonomy":"embl_taxonomy","embeddable":true,"href":"https:\/\/www.embl.org\/groups\/scientific-instrumentation-workshops\/wp-json\/wp\/v2\/embl_taxonomy?post=75"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}