@ai-matrx/capture 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -22,3 +22,26 @@ Real-phone feedback pass (the bar was eating the viewfinder):
22
22
  - New `slots.aboveBar`: host content rendered OVER the feed above the bottom bar (filmstrip home) — zero bar height.
23
23
  - Domain action returned to the mode row (absolute right of the narrow track).
24
24
  - Bottom paddings cut (mode row py-1.5, shutter row pb-1.5), thumbs 44px.
25
+
26
+ ## 0.1.2 — 2026-08-29
27
+
28
+ - Mode row: the trailing domain action is a flex SIBLING of the connected track (absolute positioning collided with the labels on narrow phones).
29
+
30
+ ## 0.2.0 — 2026-08-29
31
+
32
+ The package-completeness release: the whole capture loop now lives in the box (Arman's rule — likely to fail, likely to need tuning, or less-than-perfect unless done perfectly ⇒ in the package).
33
+
34
+ - `MediaViewer` — the full-screen swipe pager moved in: pointer-gesture paging with the real-phone-tuned thresholds (40px / 0.25 px-per-ms flick), vertical-drag dismiss, neighbor preload (±2 photos, ±1 video kept mounted + decoded), desktop keys/chevrons. Zero animation deps.
35
+ - `media-cache` — package-owned media resolution cache: memoized `resolve()` per item, in-flight dedup, LRU eviction, owned-URL revocation, `useMediaUrl`/`primeMedia`/`invalidateMedia`.
36
+ - `CaptureFilmstrip` — the over-feed thumbnail strip (uploading/error/accent states) rendered by the chrome from `media.items`.
37
+ - `CameraCapture` gained `media: CaptureMediaSession` — filmstrip → viewer → editor with REPLACE semantics (saving an edit removes the source item and its cached URL) orchestrated inside the package; hosts implement only item CRUD.
38
+ - `useDefaultCaptureEngine` + `CameraFeed` — the batteries-included engine: getUserMedia (the ONE sanctioned site, `src/engine/`), flip, full-sensor photo with center-crop aspects, MediaRecorder video with a concrete-MIME ladder and mic-optional composition, package-created upload picker. A Vite host is a few lines; AI Matrx keeps injecting its lease-managed runtime.
39
+ - Safe-area correctness in ANY host: the host-app `pt-safe`/`pb-safe`/`mb-safe` utility classes (which only exist in AI Matrx) are replaced with inline `env(safe-area-inset-*)` styles.
40
+ - Laws updated: law 2 is now "getUserMedia only inside src/engine/".
41
+
42
+ ### Also in 0.2.0 — adversarial-review fixes
43
+
44
+ - Viewer: preload slides can no longer steal touches (`pointer-events-auto` only on the ACTIVE slide — an invisible neighbor video previously sat above the stage and ate swipes); mounted preload reduced to ±1 (iOS memory), URL priming stays ±2; delete states its consequence before acting; keyboard suppressed while the editor is on top; audio items render natively (filmstrip tile + viewer slide).
45
+ - Chrome: a photo countdown is cancelled by a mode switch (it used to fire a photo mid-video); the dead `CaptureCloudPort.onSaveEdited` port is removed — the editor saves through `media.onReplacePhoto` only.
46
+ - Editor: rotate/flip BAKE into the working bitmap immediately (full-res canvas re-encode), so the crop frame always matches the pixels on screen — the CSS-transform approach diverged at 90°/270°; Save failures surface an inline error instead of silently doing nothing; baked object URLs are revoked on replace/close.
47
+ - Track controls: capabilities poll on a widening ladder (0.5s→5s) until torch/zoom/exposure appear — iPhones that report late now get their pills.
package/README.md CHANGED
@@ -4,6 +4,67 @@ The AI Matrx capture kit — the opinionated, iPhone-style camera experience as
4
4
 
5
5
  **THE CLOUD LAW:** cloud integration is WHAT this system does, not an add-on. `CameraCapture` requires a `CaptureCloudPort` (recents thumb, library opener, edited-image persistence). The host decides HOW the cloud is reached — never WHETHER.
6
6
 
7
+ ## Drop-in quickstart (any React host)
8
+
9
+ No media runtime required — the package ships its own engine:
10
+
11
+ ```tsx
12
+ import { useState } from "react";
13
+ import {
14
+ CameraCapture,
15
+ CameraFeed,
16
+ useDefaultCaptureEngine,
17
+ type CaptureMediaItem,
18
+ } from "@ai-matrx/capture/react";
19
+
20
+ export function Camera() {
21
+ const [mode, setMode] = useState<"photo" | "video">("photo");
22
+ const [items, setItems] = useState<CaptureMediaItem[]>([]);
23
+
24
+ const add = (file: File, kind: "photo" | "video") =>
25
+ setItems((xs) => [
26
+ ...xs,
27
+ { key: crypto.randomUUID(), kind, src: URL.createObjectURL(file) },
28
+ ]);
29
+
30
+ const engine = useDefaultCaptureEngine({
31
+ onPhoto: (f) => add(f, "photo"),
32
+ onVideo: (f) => add(f, "video"),
33
+ onFiles: (fs) => [...fs].forEach((f) =>
34
+ add(f, f.type.startsWith("video/") ? "video" : "photo")),
35
+ });
36
+
37
+ return (
38
+ <div style={{ position: "fixed", inset: 0 }}>
39
+ <CameraCapture
40
+ engine={engine}
41
+ preview={<CameraFeed engine={engine} />}
42
+ mode={mode}
43
+ onModeChange={setMode}
44
+ media={{
45
+ items,
46
+ onDelete: (key) => setItems((xs) => xs.filter((x) => x.key !== key)),
47
+ onReplacePhoto: (key, blob) =>
48
+ setItems((xs) => xs.map((x) =>
49
+ x.key === key
50
+ ? { ...x, src: URL.createObjectURL(blob) }
51
+ : x)),
52
+ }}
53
+ cloud={{ recentsThumb: null, onOpenLibrary: () => {/* your gallery */} }}
54
+ />
55
+ </div>
56
+ );
57
+ }
58
+ ```
59
+
60
+ That is the whole wiring: filmstrip, swipe viewer (tuned gestures + neighbor
61
+ preload + resolution caching), crop/rotate editor with replace semantics,
62
+ two-tap options grid, timer, torch/zoom (when the hardware reports them),
63
+ upload lane and safe-area handling all come from the package. Hosts with
64
+ their own camera runtime (AI Matrx) pass a custom `CaptureCameraEngine`
65
+ instead of the default one; persisted items provide `resolve()` instead of
66
+ `src` and the package caches the resolutions.
67
+
7
68
  ## What's inside
8
69
 
9
70
  - `CameraCapture` — the assembled chrome: full-bleed feed under semi-transparent near-black bars; top bar (close · center slot · torch · extras · options); real zoom pills (track capabilities only — nothing faked); VIDEO · PHOTO · UPLOAD mode row (upload is first-class); recents thumb · shutter · flip; honesty chips (recording clock survives hidden chrome).
package/dist/index.d.cts CHANGED
@@ -37,8 +37,6 @@ interface CaptureCloudPort {
37
37
  recentsThumb: React.ReactNode;
38
38
  /** Opens the host's cloud media library (tiled gallery). */
39
39
  onOpenLibrary: () => void;
40
- /** Persists an edited image produced by the edit sheet. */
41
- onSaveEdited: (blob: Blob, suggestedName: string) => void;
42
40
  }
43
41
  /**
44
42
  * The engine port — everything the chrome needs from the host's camera
package/dist/index.d.ts CHANGED
@@ -37,8 +37,6 @@ interface CaptureCloudPort {
37
37
  recentsThumb: React.ReactNode;
38
38
  /** Opens the host's cloud media library (tiled gallery). */
39
39
  onOpenLibrary: () => void;
40
- /** Persists an edited image produced by the edit sheet. */
41
- onSaveEdited: (blob: Blob, suggestedName: string) => void;
42
40
  }
43
41
  /**
44
42
  * The engine port — everything the chrome needs from the host's camera