Hybrid-Center Plan: PNG Background with Polygon Layer
Some architects or centers provide plans as high-quality raster graphics (PNG/JPEG) instead of clean vector files. To ensure such plans still function as interactive center plans, cockpitOS supports a hybrid format:
An SVG file with the PNG as an embedded background + transparent polygons as an interactive layer – optionally with a JSON containing per-shop
viewBoxfor sharp detail views on shop detail pages.
This follows the same data/display path as a "normal" SVG center plan — nothing changes during upload, mapping, or in the frontend. Thus, there is no migration and no data loss to expect.
AI-generated plans: Copy-paste starter prompts (DE/EN) v2 including topology vs. geometry, image roles, and tool recommendations → Hybrid Center Plan: AI Master Prompt.
When Does It Make Sense?
- The plan comes as PNG/JPEG from the architect and contains many intricate graphic details (shadows, textures, symbols) that would be tedious to reconstruct as vectors.
- You still want clickable/hoverable shops, services, etc. with everything that cockpitOS wayfinding offers.
- A sharp detail view should be visible on the shop detail page.
Resolution, Zoom — Plus and Minus
The big advantage: You can design the plan visually — shadows, textures, icons, beautiful colors, everything that AI tools or graphic programs excel at. This often appears significantly higher quality on the website than a plain vector floor plan.
What you should consider: The background is an image, not an infinitely sharp vector. Therefore:
- Resolution: Preferably large and sharp (typically at least 2000–3000 px on the longer edge; for very large centers, even more). A small, blurry image will become soft or pixelated when zooming in the plan or on detail views.
- Zooming in significantly on the overall view may become visible — this is normal with raster plans. For shop detail pages, Cockpit can optionally provide sharp views (
shopViewBoxes); this is worth a good source image. - Classic SVG from Illustrator remains unbeatable if you need to zoom extremely close or if the plan is constantly vectorized.
In short: Hybrid = Top appearance and quick start (e.g., AI image → Cockpit). Trade-off = Image quality and resolution must be considered, not just "any small PNG."
Structure of a Hybrid-SVG
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 1600 1200">
<!-- 1) Raster background: the PNG embedded as a Data-URL OR as an external URL -->
<image x="0" y="0" width="1600" height="1200"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…" />
<!-- Alternatively: href="https://cdn.cockpitos.dev/centers/<id>/centerplan/plan.png" -->
<!-- 2) Optionally: mark group as "hover-layer" – ensures that the polygons remain invisible and are only slightly colored on hover. -->
<g id="hover-layer">
<!-- Shops: each ID follows the convention shop-XX -->
<polygon id="shop-EG-29" points="180,120 270,120 270,180 180,180" fill="none" />
<polygon id="shop-EG-30" points="280,120 370,120 370,180 280,180" fill="none" />
<!-- Services -->
<polygon id="service-OG-stairs" points="…" fill="none" />
<polygon id="service-OG-elevator" points="…" fill="none" />
</g>
</svg>
Important:
- The
<image>must cover the entire plan. The SVG'sviewBoxshould reflect the image's size (e.g., PNG is 1600×1200 →viewBox="0 0 1600 1200"). - Polygons get
fill="none"orfill-opacity="0"– this makes them invisible but still capture clicks/hover. - IDs follow the convention
shop-…,service-…,entrance-…(see SVG Structure). Optionally, the polygon layer can be wrapped in<g id="hover-layer">– cockpitOS will then automatically ensure a transparent presentation with light hover coloring. - The CSS in the frontend sets
pointer-events: nonefor<image>, so all clicks reliably target the polygons.
Variant A (recommended): Automatic Segmentation in the Dashboard
cockpitOS can transform a PNG/JPEG directly in the dashboard into a Hybrid-SVG with a polygon layer. You do not need Inkscape or external tools — just the center plan as an image file.
Workflow
New floor with raster directly: Under Center Plans → New Floor, you can select the "Raster (Hybrid)" tab in the dialog and upload PNG/JPEG/WebP. After saving, the floor will open with the "SVG-Centerplan" tab active, so you can continue with auto-segmentation (as with existing floors).
- Open the floor:
Center Plans → Edit Floor → Tab "SVG-Centerplan". - In the first card "PNG → Hybrid-SVG (automatic segmentation)":
- Upload center plan (PNG, JPEG, or WebP).
- Pick a recognition type — in most cases Normal Plan (no sliders needed). Alternatives: Small Areas (elevators, restrooms), AI-generated plan (images from AI tools).
- Click "Detect areas" → preview with polygon count.
- If the result is off, helper buttons appear (e.g. "Find more areas", "Fewer noise spots").
- Sliders only under "Expert settings (optional)" — for edge cases.
- Before major changes: "Save current SVG" or "Download Hybrid-SVG" in the card below.
- Then switch to the "Polygon Editor" tab and assign each polygon its final ID convention (see below).
Later Exchange of the Plan Image (Retaining Polygons)
If the architect or AI provides a revised PNG/JPEG (new format, additional elements, different colors), but the polygon assignments in the cockpit should remain:
- Open floor → Tab "SVG-Centerplan" → Card "PNG → Hybrid-SVG".
- Upload new image – the UI automatically switches to the "Replace Background (Retain Polygons)" mode.
- "Generate Preview" → check if the new raster fits (note on differing aspect ratio).
- "Adopt Background" – updates
mapSvg(<image xlink:href="…">) andmapImagein the database; polygon IDs and MapLocations remain unchanged. - Center website cache will be invalidated (ISR Revalidation).
Important: The "Additive Add" mode only segments additional polygons from the new image – it does not replace the visible background. "Completely Replace" discards all existing polygons and starts anew.
Recommendation: Keep the same aspect ratio as during the initial upload (polygons are located on the existing SVG canvas). Significantly different proportions may slightly distort the image; the click areas remain at the old coordinates.
Alternatively (externally): Download Hybrid-SVG, replace the raster in Inkscape, re-upload the SVG – works, but is more error-prone than the Cockpit mode above.
What the Parameters Do
Editorial: Three recognition types in the dashboard replace most sliders. Expert settings only for edge cases. Technical reference:
| Recognition type | When | Roughly maps to |
|---|---|---|
| Normal Plan | Default for architect PNGs | Default parameters |
| Small Areas | Elevators, restrooms, logos missing | Lower minimum size, higher color tolerance |
| AI-generated plan | Image from AI master prompt | Stricter colors + higher contour threshold |
| Fewer noise spots | Too many mini-polygons (helper button after preview) | Higher minimum size |
| Parameter (expert) | Effect | Default |
|---|---|---|
| Color Tolerance | How much pixels can differ in color to count as the same region. Higher = more generous grouping (Risk: shops merge). | 30 |
| Minimum Size (Pixels, downscaled) | Regions smaller than this value are discarded as "noise". Increase if too many mini-polygons appear. | 200 |
| Background Tolerance | Pixels with a distance ≤ this value to the dominant corner color are ignored as background. | 40 |
| Polygon Simplification (Pixels) | Douglas-Peucker epsilon. Higher = fewer vertices (smaller SVG, slightly more angular polygons). | 1.5 |
| Max Processing Size | Limits the image dimension for processing (performance). Original dimensions are retained in the final SVG. | 1500 |
How It Works Technically
- Load Image: Bunny URL →
sharp(libvips) → RGBA pixel buffer. - Downscale to max. ~1500 px edge length (purely for performance; the polygon coordinates are scaled back to the original dimensions at the end).
- Detect Background: Median color of the four image corners (with inset).
- Connected Components per Flood Fill with color tolerance – each contiguous non-background area becomes a region.
- Filter: Minimum pixel count + maximum share (prevents large background areas from being misclassified as "regions").
- Boundary Tracing (Moore neighborhood) → closed outer contours.
- Douglas-Peucker Simplification → more compact polygon points.
- Build Hybrid-SVG with
<image>(Bunny URL) +<g id="shops">full of<path>elements with IDs likeshop-EG-tbd-01,shop-EG-tbd-02, …
The floor prefix (EG, OG1, …) is automatically derived from the floor name so that the polygons match directly with the editor workflow.
Data Loss Protection
- Preview first, Apply only explicitly: There is no auto-apply.
- Existing
mapSvgblocked: If the floor already has an SVG, the server rejectsmode=applywithoutreplaceExisting: true. The UI explicitly asks for confirmation and offers to download the current SVG beforehand. shopViewBoxesremains untouched: Thetbd-XXprovisory IDs are irrelevant for the existing viewBox map – they only fit after the ID assignment in the polygon editor.
Practice: Contours, Services, Entrances, Decorative Elements
Contours around Shop Areas
Most center plans have dark contour lines between shops – this is invaluable for detection. The card features the slider "Contour Threshold (Luminance)" (default 60). This treats all dark pixels as background before the flood-fill:
- Effect 1: Contours completely disappear from the polygons instead of being segmented as a huge, unsightly "line polygon."
- Effect 2: Polygons end neatly at the contour, not through it – the preview looks much tidier.
- Effect 3: Neighboring shops with nearly identical colors are separated more reliably, as the contour blocks the flood-fill.
Tips:
- If your plan has very thin, light gray contours: Increase the threshold (e.g., 90) until the lines drop out.
- If your plan has no contours at all (only solid color areas): Set the threshold to 0; otherwise, dark shops will be erroneously treated as background.
- If line remnants still remain: The advanced options Aspect Ratio (default 12) and Compactness (default 0.15) discard elongated or holey regions.
Services (Elevator, Escalator, WC)
Service symbols are usually much smaller than shops in the PNG. Recommended workflow:
- First Pass:
Polygon Layer = Shops, minimum size 200, mode "Completely Replace." Delivers the large shop polygons. - Second Pass on the same PNG:
Polygon Layer = Services, reduce the minimum size to, e.g., 50, mode "Additive Add." Delivers the small service symbols as additional polygons, added to the existing SVG – shops remain unchanged. - Third Pass for logos similarly (
Polygon Layer = Logos, possibly even smaller minimum size).
Then in the Polygon Editor, assign descriptive suffixes to the service symbols (stairs, elevator-1, wc-ladies, …).
Entrances
Entrances in the PNG often feature arrow symbols on the outside. The auto-segmenter usually detects them but does not automatically assign them to the convention – this makes sense as "the main access" is a content decision. Procedure:
- The arrows will either be recognized in the first shop pass (then click in the polygon editor → set layer to "entrance" → suffix
main/north/parking garage→ enter) or will remain unsegmented. - If the PNG has no arrow symbols: draw a small polygon over the entrance in Inkscape, ID
entrance-main, re-upload the SVG.
Decorative Elements (Plants, Benches, Shadows, Scale, Compass Rose)
In the polygon editor, there are two dedicated actions:
- "Mark as decorative" moves the polygon to
<g id="decorative">withpointer-events: none. The polygon remains in the SVG (for future Inkscape round trips) but is neither displayed nor clickable on the live center plan page. In the editor itself, it appears as a gray-hatched polygon and can be returned to interactive status anytime by clicking "Interactive Again." - "Remove Polygon" deletes the polygon hard from the SVG with a confirmation dialog. Useful for unmistakable trash: shadows, scale bars, north arrows, compass roses.
Multi-selection (marquee)
With the Select tool you can drag a rectangle on the plan (like in graphic apps):
- Drag on empty area → all polygons in that box are selected (blue).
- Shift + click on individual areas → add/remove from selection.
- Shift + drag → add to existing selection.
- Delete or sidebar "Delete (N)" → remove all selected areas at once.
- "Decorative only (N)" → mark all selected areas as decorative in one step.
Shop assignment remains single-select (click one area → enter number).
Auto-Save: Changes in the polygon editor are automatically written to the database after a short pause (Status "Saved" at the top). You can still click "Save" optionally.
When saving, any linked shop mappings are also seamlessly carried along: If a previously mapped polygon is set to "decorative," the MapLocation entry will link to the new decorative-… ID instead of going to null – the mapping is not lost but rendered inert for the visitor.
Variant B: Manual Hybrid-SVG in Inkscape or Affinity Designer
- New SVG Document with the size of your PNG (e.g., 1600×1200 px).
- Embed PNG: File → Import → Select PNG → Option "embed" (not "link"). In Inkscape, you can additionally open
Edit → XML Editorafter import and ensure that the<image>element has axlink:href="data:image/png;base64,…". - Create Hover Layer: New group or layer with ID
hover-layer. - Draw Polygons: Overlay a polygon over every shop or service area.
- Fill: none (transparent)
- Stroke: none (or thin, just for orientation during editing)
- Set ID: Through the object properties panel (
Ctrl + Shift + Oin Inkscape), e.g.,shop-EG-29,service-OG-stairs.
- Save as "Clear SVG" (Inkscape) or "Export SVG" (Affinity).
- Upload in the dashboard →
Center Plans → Edit Floor → SVG-Centerplan. During upload, Bunny CDN, viewBox normalization, and shop detection are handled automatically.
Tip: If you want to maintain the PNG centrally, you can upload it separately as
mapImage(Bunny now also allows PNG/JPEG/WebP for center plans) and then link to it in the SVG viaxlink:href. This allows you to later change the background without modifying the SVG.
Step 4 (alternative): Assign IDs Directly in the Dashboard
If the SVG already contains polygons whose IDs do not yet comply with the convention (e.g., because they come from an automatic PNG color segmentation and have names like shop-EG-tbd-12), you can make the final assignment directly in the dashboard without Inkscape:
- Open the center plan editor and access the tab "Polygon Editor."
- Auto-recognized areas: Click on the red area → enter Type (Shop/Service) and Number or Name → Assign & Next.
- Trace missing areas (toolbar above the plan):
- Rectangle: Click two diagonally opposite corners (typical for shop floor plans).
- Circle: Click the center, then a point on the edge (round islands, columns).
- Corners: Any shape – click corners in sequence, then Enter, right-click, or "Finish Shape" (min. 3 corners).
- Keys: 1 Select · 2 Rectangle · 3 Circle · 4 Corners · Enter Assign or finish shape · right-click finish/end · Esc cancel.
- The editor shows the progress X/Y at the top.
- "Save" persists the updated SVG along with the ID renames in the database.
In the SVG-Centerplan tab, there are only Standard / Small Areas options for auto-recognition – fine-tuning is only available under "Fine Adjustment."
What Happens Automatically When Saving
- The polygon receives the convention ID
<layer>-<floorPrefix>-<suffix>and is sorted into the appropriate layer group (<g id="shops">,<g id="services">, …). The floor prefix is derived from the floor name (Ground Floor→EG,1st Upper Floor→OG1, …). - A new entry will be added to
shopViewBoxesfor the new ID (bounding box + 12 px padding), if not already present. - Existing
MapLocation.svgIdlinks will be renamed – no lost mapping. This occurs atomically in a transaction: First, all affected MapLocations are temporarily marked, then set to the new ID, ensuring that renames do not interfere with each other. - Caches (Redis Shop-Mapping, Center Website ISR) are invalidated.
- Intermediate states are saved locally in the browser (localStorage) to prevent loss of work – but nothing is written to the DB without explicit "Save."
Existing centers are risk-free: Polygons that are already correctly named (
shop-29) are recognized by the editor as "assigned" (green) and remain unchanged. Anyone with no need can simply ignore the tab.
Detail Views (shopViewBoxes)
On shop detail pages, cockpitOS offers a sharp vector section of the center plan. By default, CSS transform zooms to the shop's bounding box – this always works, but it's less elegant with hybrid plans because the PNG may then become pixelated.
With shopViewBoxes (manageable per floor in the dashboard), the SVG viewBox is instead specifically set to the appropriate section. The result:
- Vector Scaling – always sharp
- Reuse of the same SVG file – no need to crop images
- Consistent look across all devices (Retina, App WebViews)
How to Manage the Sections in the Dashboard
- Open
Center Plans → Edit Floor → Tab "SVG-Centerplan." - Below the upload field, you will find the card "Detail Page Sections."
- Click "Automatically Calculate Missing" – the system will create a
viewBoxproposal for each found shop/service (based on the bounding box + freely selectable padding). - Individual values can be further refined through input fields.
- Save writes the JSON map to
MapFloor.shopViewBoxes.
If you do not wish to manage sections, simply leave the field empty – the frontend will then automatically use the classic DOM zoom. It is a purely additive, optional feature.
JSON Format (for Developers)
{
"shop-EG-29": { "viewBox": "180 120 90 60", "padding": 8 },
"service-OG-stairs": { "viewBox": "300 50 50 80" }
}
- Key = SVG Element ID (or
data-shop-id). viewBox= Standard SVG viewBox as a string"minX minY width height".paddingis optional and only informative (saved during auto-calculation).
What Happens Internally?
| Step | Component / File |
|---|---|
| Upload (Bunny CDN, now also PNG/JPEG/WebP for center plans) | apps/dashboard/src/app/api/upload/bunny/route.ts |
viewBox Normalization (now including <image> BBox) | apps/dashboard/src/lib/wayfinding/svg-viewbox-normalizer.ts |
| Shop Detection (unchanged, IDs according to convention) | apps/dashboard/src/lib/wayfinding/svg-analyzer.ts |
Frontend: pointer-events for <image> | packages/wayfinding/src/components/InteractiveFloorPlan.tsx |
Detail Embed: presetViewBox from DB | apps/center-website/components/shop-detail-center-plan-embed.tsx |
| Helper Lib: parse/serialize/auto-calculate | packages/wayfinding/src/lib/wayfinding/shop-viewboxes.ts |
| Helper Lib: parse/rename polygons/sort into layers | packages/wayfinding/src/lib/wayfinding/svg-polygon-editor.ts |
| Helper Lib: manual tracing (rectangle/circle/corners) | packages/wayfinding/src/lib/wayfinding/svg-polygon-draw.ts |
| Helper Lib: image segmentation (Flood Fill, Boundary Tracing, Douglas-Peucker, SVG Builder) | packages/wayfinding/src/lib/wayfinding/image-segmentation.ts |
| Server Wrapper: sharp + pixel extraction | apps/dashboard/src/lib/wayfinding/server-image-segment.ts |
| Dashboard UI: viewBox map | apps/dashboard/src/components/wayfinding/ShopViewBoxesCard.tsx |
| Dashboard UI: Polygon Editor | apps/dashboard/src/components/wayfinding/PolygonAssignmentEditor.tsx |
| Dashboard UI: PNG Auto-Segmentation | apps/dashboard/src/components/wayfinding/AutoSegmentPngCard.tsx |
| Atomic Save (mapSvg + viewBoxes + MapLocation-Sync) | apps/dashboard/src/app/api/wayfinding/floors/[floorId]/polygon-edits/route.ts |
| API: PNG Auto-Segmentation (Preview + Apply) | apps/dashboard/src/app/api/wayfinding/floors/[floorId]/auto-segment-png/route.ts |
| DB Field | MapFloor.shopViewBoxes (TEXT, nullable) – see SAFE migration 20260514_add_map_floor_shop_view_boxes_SAFE.md |
What Does Not Change for Existing Centers
- Existing pure vector SVGs will continue to be displayed identically — neither click logic nor viewBox normalization behaves differently.
- The new DB field
shopViewBoxesis optional (nullfor all existing floors). As long as it remains empty, the existing DOM zoom will continue. - The Bunny upload type
centerplancontinues to accept SVG; additionally, PNG/JPEG/WebP are now allowed – nothing disappears.
Cross References
Nutzungsstatistik: Seitenaufrufe werden anonymisiert erfasst. Im Umami-Dashboard nach diesem Pfad filtern: /en/centerplan/hybrid-png-mit-polygonen