# Detaildrift 1.0

An original jQuery image zoom and pan component, with a local studio and a filled, fictional campus example. The reusable plugin is the product; the studio makes it easy to configure and export a working viewer.

**Distribution:** the download contains the reusable runtime, local studio, four filled samples, this guide, scope/offer documentation and license notices. It needs no build or package installation. Local maintenance verification and independent release checks are recorded separately from the customer download.

## Start the studio

Unzip the download without changing its folder structure. No npm install or build is needed to use it. Serve the extracted folder with a static HTTP server, for example:

```sh
python3 -m http.server 8787 --bind 127.0.0.1 --directory /path/to/detaildrift
```

Open `http://127.0.0.1:8787/app/index.html`. A local HTTP server allows the studio to read its bundled export runtime. The downloaded standalone HTML is self-contained. File-origin launch of the studio is not supported. Nothing uploads to a server, analytics service or account.

## Create a viewer

1. Start with the included Harbor Works site diagram, or choose your own PNG, JPEG, WebP or GIF (8 MiB / 40 million pixels maximum). SVG uploads are intentionally excluded.
2. Focus the image by clicking it. Use the wheel, double-click or +/− buttons to zoom; drag to pan. Keyboard: +/− zoom, arrows pan, F or 0 fit, 1 actual pixels. Fit is the minimum magnification. Actual pixels respects the configured zoom bound, so very large images can reach the maximum first.
3. Add a title and useful image description. Choose 4×, 8×, 12× or 16× fit magnification. Click Apply settings.
4. Save project downloads a versioned JSON file that embeds the image, settings and view. Open project restores it with a file chooser. Ctrl/Command+S saves pending title/description too. Keep this file as your portable backup.
5. Export standalone HTML downloads a complete viewer with image, original component, CSS, geometry and bundled jQuery. It has no external runtime dependency. You can host that HTML or put it in an iframe. For CMS integration, use the reusable component below rather than pasting a full HTML document into a content field.

An automatic browser draft stores the applied settings and latest view when browser storage permits. Large artwork may exceed storage quota; the studio then tells you to save a project. Private browsing and cleared site storage can remove drafts. Invalid image/project imports preserve current artwork and view. Creating another project replaces the current browser draft; save a project before doing so.

## Save inspection destinations

Use **Saved inspection views** below the viewer to guide visitors to important parts of the same image. Zoom and pan to a detail, enter a unique name such as “Makers Yard”, and choose **Save current view**. Save up to six positions. Choose a saved name to return there; Remove deletes that position from the current project. This changes navigation only: it adds no image marks, annotations or editing.

Save project retains names and normalized zoom/center values in the optional version 1 `inspectionViews` array. Open project restores them. Old version 1 projects without this field continue to work. A replacement image clears saved positions so they cannot silently point to unrelated artwork; save a JSON backup before replacing an image. Lowering the zoom limit clamps saved magnifications to that limit when settings are applied or downloaded.

The actual HTML export includes native, keyboard-accessible destination buttons above the image. Visitors can jump to an authored detail and still use ordinary zoom, pan, Fit and actual pixels. Buttons wrap on narrow screens. All destinations, image and runtime remain in the same self-contained file; no service or network lookup is added. An older Detaildrift runtime will ignore the optional field and requires re-export from the updated studio to display these buttons. Direct jQuery integrations can use the unchanged `setState` method with saved positions; the plugin API is unchanged.

## Integrate in an existing jQuery site

Keep your existing compatible jQuery instance; do not load a second copy. The bundled demonstration uses jQuery 3.7.1. Copy `app/geometry.js`, `app/detaildrift.js`, `app/detaildrift.css` and your image into your project. Load CSS in the head, then scripts after the viewer element:

```html
<link rel="stylesheet" href="detaildrift.css">
<div id="plan" style="height:540px"></div>
<script src="jquery-3.7.1.min.js"></script>
<script src="geometry.js"></script>
<script src="detaildrift.js"></script>
<script>
jQuery('#plan').detaildrift({
  src: 'your-image.jpg',
  alt: 'Describe the significant image content',
  maxZoom: 8
});
</script>
```

Use a same-origin image URL or an image URL your browser permits. A failed replacement emits an error and preserves the current image. The studio accepts only embedded raster data for portable projects. No image editing, annotation or image conversion is included. Large image decoding can use substantial browser memory; this is not a tiled gigapixel viewer.

`src` is required. `alt` defaults to “Detailed image”. `maxZoom` is a finite number from 2 to 16, relative to the container's fit scale. Size the host using CSS; ResizeObserver follows its size and preserves the normalized subject center where bounds permit. Viewport and image bounds can force the center toward the middle. Hidden/zero-size containers are painted correctly once laid out.

| jQuery method | Behavior |
|---|---|
| `.detaildrift(options)` | Initialize each element once; chainable |
| `.detaildrift('zoomIn')` / `'zoomOut'` | Multiply/divide fit zoom by 1.4 |
| `.detaildrift('zoom', factor, x?, y?)` | Zoom around viewport coordinates, center by default |
| `.detaildrift('pan', dx, dy)` | Pan in viewport CSS pixels, bounded |
| `.detaildrift('fit')` / `'actual'` | Fit image / actual pixel magnification within limits |
| `.detaildrift('getState')` | First instance's defensive `{zoom,centerX,centerY}` copy |
| `.detaildrift('setState', state)` | Validate and restore normalized state after ready |
| `.detaildrift('setImage', src, alt?)` | Load replacement, then reset to fit on success |
| `.detaildrift('destroy')` | Disconnect listeners/observer and restore original content/attributes |

`detaildrift:ready` supplies `{width,height}` as the second handler argument; `detaildrift:change` supplies the state; `detaildrift:error` supplies a readable message. Bind ready before initialization to restore saved state. Each host is independent. `samples/integration.html` demonstrates two simultaneous instances and destroy/reinitialize.

## Accessibility and input

The viewer is a named focusable region, with labeled buttons and native focus indicators. Wheel zoom activates only while the viewer or its controls have focus; otherwise the page scrolls normally. Image alternative text and the visible description should explain meaningful content. A diagram's information may require a separate text equivalent. Pointer Events implement single-finger pan and two-pointer pinch on the viewer; normal page scrolling remains available outside it. Only the first two contacts are tracked; extra contacts are ignored. Lifting one tracked contact continues with the remaining contact. Pointer cancellation, viewer/window focus loss, artwork replacement and destroy cancel active drags and release captures, so returning movement cannot drag the previous artwork. Keyboard and buttons remain available. A narrow desktop browser viewport does not certify physical touch behavior or every browser engine. Check actual devices in your supported audience before shipping an integration.

## What is in the download

- `app/`: local studio and reusable viewer runtime (seven files).
- `vendor/`: jQuery 3.7.1 and its MIT notice.
- `samples/`: Harbor Works PNG, editable project JSON, ready-to-use standalone HTML and a two-instance integration example.
- `README.md`, `SPEC.md`, `OFFER.md`, `LICENSE.txt`, `THIRD_PARTY.md`: setup, scope and rights.

Open `samples/harbor-viewer.html` directly for a self-contained filled viewer. Run the studio over local HTTP as shown above to create your own output. The archive contains 18 customer files; it excludes internal QA screenshots, receipts, corrupt-input fixtures, development tests/scripts, npm manifests and the hosted measurement adapter. The download has no dependency on those excluded files.

The maintained source repository additionally holds developer tests, package tooling, `distribution-layout.json` (the exact customer allowlist) and QA evidence. From that source checkout, developers can run `npm ci`, `npm test` and `python3 scripts/package.py`. These commands are not installation steps for the customer download. The package command fails on a missing customer file and never recursively collects QA directories. Evidence and completion bindings stay in the source checkout; fresh QA and independent review are required after source changes.

User artwork remains yours. Free personal/commercial use and export rights follow the included Nishvault terms; reselling or redistributing this complete product as a competing product is excluded. Detaildrift remains the existing free image-viewer baseline. Gesture lifecycle refinements maintain that customer job; a differently named diagram or gesture option does not establish a separate finished customer outcome.

## Hosted usage measurement

In the maintained source checkout only, `app/hosted-metrics.js` is an optional first-party adapter for the exact HTTPS Nishvault product/editor routes. The publisher loads it only on hosted pages. Offline `app/index.html`, the reusable jQuery component and exported standalone viewers do not load it. The studio keeps its existing local HTTP reads for the bundled sample/export runtime; this change adds no application network request to the offline studio or the viewer. The content-free `detaildrift:export-created` event fires only after validated standalone HTML is generated and its download dispatched, with `{format:'html'}`. JSON backups, zoom/pan and failed generation/downloads do not count as export completion.

The adapter sends fixed anonymous diagnostic `page_view`, `product_export` and `calculator_result` (the endpoint's existing completion event) payloads to `/api/metrics`. No image, project, title, alt text, filename, view coordinates, URL query, visitor/session ID, referrer or cookies are sent. DNT/GPC disable it. It creates no storage, permits one view/completion and at most 20 export events per document, and does not retry failures or interrupt editing. Synthetic hosted QA uses `?nv_internal_test=1`. Event counts do not prove unique people, signed canonical funnels, sales or retained files. Actual production integration/persistence requires separate release evidence.
