@popmelt.com/core 0.18.0 → 0.18.2
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/README.md +99 -0
- package/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/dist/adapter-react-three-fiber.d.mts +36 -0
- package/dist/adapter-react-three-fiber.mjs +2 -0
- package/dist/adapter-three.d.mts +2 -0
- package/dist/adapter-three.mjs +1 -1
- package/dist/bridge-entry.mjs +54 -54
- package/dist/chunk-J3UIBBU2.mjs +2 -0
- package/dist/{chunk-RS3XXK26.mjs → chunk-RH6W4F2W.mjs} +1 -1
- package/dist/{chunk-GQOEG3E5.mjs → chunk-UC34UP4S.mjs} +1 -1
- package/dist/cli.mjs +74 -74
- package/dist/index.d.mts +36 -8
- package/dist/index.mjs +40 -40
- package/dist/media.d.mts +3 -2
- package/dist/media.mjs +1 -1
- package/dist/plugin-astro.mjs +1 -1
- package/dist/plugin-vite.mjs +1 -1
- package/dist/{server-MUVH7FWR.mjs → server-PV5AVWEM.mjs} +56 -56
- package/dist/server.d.mts +2 -2
- package/dist/server.mjs +56 -56
- package/dist/{video-adapter-DzNtG67g.d.mts → subjects-CeqtFged.d.mts} +1 -337
- package/dist/video-adapter-Gq8saCDn.d.mts +339 -0
- package/package.json +14 -4
package/README.md
CHANGED
|
@@ -158,6 +158,40 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
|
|
158
158
|
|
|
159
159
|
`navigate` is optional for single-page use. Pass your router's navigation function when Popmelt needs to restore annotations across routes.
|
|
160
160
|
|
|
161
|
+
### Add application context to comments
|
|
162
|
+
|
|
163
|
+
Use `getCommentMeta` to snapshot application-owned context whenever a human
|
|
164
|
+
submits annotations or replies in a thread. Popmelt validates and detaches the
|
|
165
|
+
JSON, includes it as contextual evidence for the model, and persists the same
|
|
166
|
+
snapshot with the stored human turn.
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
<PopmeltProvider
|
|
170
|
+
getCommentMeta={({ kind }) => ({
|
|
171
|
+
'my-app/video-ui/v1': {
|
|
172
|
+
kind,
|
|
173
|
+
generation: {
|
|
174
|
+
prompt: generation.prompt,
|
|
175
|
+
dataVersion: store.getState().version,
|
|
176
|
+
},
|
|
177
|
+
frame: {
|
|
178
|
+
assetId: video.id,
|
|
179
|
+
timeMs: Math.round(video.currentTime * 1000),
|
|
180
|
+
},
|
|
181
|
+
interactions: recorder.snapshot(),
|
|
182
|
+
},
|
|
183
|
+
})}
|
|
184
|
+
>
|
|
185
|
+
{children}
|
|
186
|
+
</PopmeltProvider>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The hook may be synchronous or asynchronous. Return a plain JSON object; use a
|
|
190
|
+
namespaced, versioned key so multiple integrations can coexist. Comment
|
|
191
|
+
metadata is limited to 64 KiB per human turn. Keep large binaries and long
|
|
192
|
+
event logs in external storage or attachments and place their stable IDs,
|
|
193
|
+
hashes, and timestamps in `meta`.
|
|
194
|
+
|
|
161
195
|
### Next.js
|
|
162
196
|
|
|
163
197
|
Next.js needs both the command wrapper and the config wrapper.
|
|
@@ -243,6 +277,71 @@ If the toolbar opens but cannot reach an AI, check that:
|
|
|
243
277
|
- The framework plugin or config wrapper is installed
|
|
244
278
|
- The development server was restarted after installation
|
|
245
279
|
|
|
280
|
+
## React Three Fiber
|
|
281
|
+
|
|
282
|
+
Popmelt can target objects rendered by React Three Fiber while Core continues to
|
|
283
|
+
own the familiar hover, annotation, and thread presentation. Install the R3F
|
|
284
|
+
peers alongside Core:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
npm install @popmelt.com/core @react-three/fiber three
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Keep `PopmeltProvider` outside the canvas and mount `PopmeltThreeAdapter` inside
|
|
291
|
+
it. The adapter renders nothing; it registers the current scene, camera, and
|
|
292
|
+
renderer with the nearest provider.
|
|
293
|
+
|
|
294
|
+
```tsx
|
|
295
|
+
import { Canvas } from '@react-three/fiber';
|
|
296
|
+
import { PopmeltProvider } from '@popmelt.com/core';
|
|
297
|
+
import { PopmeltThreeAdapter } from '@popmelt.com/core/react-three-fiber';
|
|
298
|
+
|
|
299
|
+
export function ProductPreview() {
|
|
300
|
+
return (
|
|
301
|
+
<PopmeltProvider>
|
|
302
|
+
<Canvas>
|
|
303
|
+
<PopmeltThreeAdapter />
|
|
304
|
+
<ProductScene />
|
|
305
|
+
</Canvas>
|
|
306
|
+
</PopmeltProvider>
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Named objects receive readable labels automatically. Add stable application
|
|
312
|
+
identity when object names or scene ordering may change:
|
|
313
|
+
|
|
314
|
+
```tsx
|
|
315
|
+
<mesh
|
|
316
|
+
name="Bottle"
|
|
317
|
+
userData={{ popmeltId: 'hero-bottle', popmeltLabel: 'Hero bottle' }}
|
|
318
|
+
>
|
|
319
|
+
{/* geometry and material */}
|
|
320
|
+
</mesh>
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Use a distinct `id` for each adapter when a page owns multiple canvases. Pass
|
|
324
|
+
`root` to target only one scene subtree, `captureFrame={false}` to omit renderer
|
|
325
|
+
screenshots, or `select`, `key`, `label`, and `describe` to adapt an application's
|
|
326
|
+
scene semantics.
|
|
327
|
+
|
|
328
|
+
For integrations that need the registered adapter instance, use the hook inside
|
|
329
|
+
the canvas instead of the component:
|
|
330
|
+
|
|
331
|
+
```tsx
|
|
332
|
+
import { usePopmeltThreeAdapter } from '@popmelt.com/core/react-three-fiber';
|
|
333
|
+
|
|
334
|
+
function ProductPopmeltAdapter() {
|
|
335
|
+
const adapter = usePopmeltThreeAdapter({ id: 'product-preview' });
|
|
336
|
+
// Optional application-specific coordination with adapter.
|
|
337
|
+
void adapter;
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
The component is the recommended default; the hook exposes the same lifecycle
|
|
343
|
+
for advanced composition.
|
|
344
|
+
|
|
246
345
|
## Media annotation
|
|
247
346
|
|
|
248
347
|
Manual image and video annotation are enabled by default in `PopmeltProvider`,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Camera, Object3D, Raycaster } from 'three';
|
|
2
|
+
import { P as PopmeltSubjectAdapter } from './subjects-CeqtFged.mjs';
|
|
3
|
+
|
|
4
|
+
type ThreeSubjectAdapterOptions = {
|
|
5
|
+
/** Unique adapter identity when a page owns more than one Three.js surface. */
|
|
6
|
+
id?: string;
|
|
7
|
+
canvas: HTMLCanvasElement;
|
|
8
|
+
camera: Camera;
|
|
9
|
+
scene: Object3D;
|
|
10
|
+
raycaster?: Raycaster;
|
|
11
|
+
/** Select a meaningful parent from the raw intersected render object. */
|
|
12
|
+
select?: (object: Object3D) => Object3D | null;
|
|
13
|
+
/** Override durable identity. Explicit application IDs are preferred. */
|
|
14
|
+
key?: (object: Object3D) => string | null | undefined;
|
|
15
|
+
label?: (object: Object3D) => string;
|
|
16
|
+
/** Add application-specific provenance or source hints to the model context. */
|
|
17
|
+
describe?: (object: Object3D) => Record<string, string | undefined>;
|
|
18
|
+
/** Capture the renderer's current frame for DOM-cloned screenshots. */
|
|
19
|
+
captureFrame?: () => string | null | Promise<string | null>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type PopmeltThreeAdapterOptions = Omit<ThreeSubjectAdapterOptions, 'canvas' | 'camera' | 'scene' | 'captureFrame'> & {
|
|
23
|
+
/** Scene root Popmelt should target. Defaults to the complete R3F scene. */
|
|
24
|
+
root?: Object3D;
|
|
25
|
+
/** Override frame capture, or set false to omit renderer screenshots. */
|
|
26
|
+
captureFrame?: ThreeSubjectAdapterOptions['captureFrame'] | false;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Register an R3F-owned Three.js scene with the nearest PopmeltProvider.
|
|
30
|
+
* Must run inside Canvas so React Three Fiber's renderer state is available.
|
|
31
|
+
*/
|
|
32
|
+
declare function usePopmeltThreeAdapter(options?: PopmeltThreeAdapterOptions): PopmeltSubjectAdapter;
|
|
33
|
+
/** Declarative, zero-render integration for use inside an R3F Canvas. */
|
|
34
|
+
declare function PopmeltThreeAdapter(props: PopmeltThreeAdapterOptions): null;
|
|
35
|
+
|
|
36
|
+
export { PopmeltThreeAdapter, type PopmeltThreeAdapterOptions, usePopmeltThreeAdapter };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";import{b as g}from"./chunk-J3UIBBU2.mjs";import{useThree as M}from"@react-three/fiber";import{useEffect as C,useMemo as E}from"react";import{Box3 as x,Raycaster as D,Vector2 as T,Vector3 as P}from"three";function h(e){return[e.x,e.y,e.z].map(r=>Number(r.toFixed(4))).join(", ")}function y(e){let r=e.material;return r&&(Array.isArray(r)?r:[r]).map(n=>n.name?.trim()||n.type).filter(Boolean).join(", ")||void 0}function j(e,r,s){let c=e.domElement.width,n=e.domElement.height;if(c<=0||n<=0)return null;let l=e.getRenderTarget(),t=e.xr.enabled;try{return e.xr.enabled=!1,e.setRenderTarget(null),e.render(r,s),e.domElement.toDataURL("image/png")}catch{return null}finally{e.setRenderTarget(l),e.xr.enabled=t}}function A(e){let c=(e.parent?.children??[]).filter(t=>t.type===e.type&&t.name===e.name),n=Math.max(0,c.indexOf(e)),l=e.name.trim()||e.type;return`${encodeURIComponent(l)}[${n}]`}function f(e){let r=[],s=e;for(;s?.parent;)r.push(A(s)),s=s.parent;return r.reverse().join("/")}function v(e){let r=e.userData.popmeltId;return typeof r=="string"&&r.trim()?r.trim():f(e)}function S(e){let r=e.userData.popmeltLabel;return typeof r=="string"&&r.trim()?r.trim():e.name.trim()||e.type}function F(e){let r=e;for(;r.parent;){let s=r.name.trim(),c=s.match(/^(.*)_(?:alpha|normal|material)(?:_\d+)+$/i),n=r.parent;for(;n.parent&&!n.name.trim();)n=n.parent;let l=n.name.trim();if(!l||!s.startsWith(`${l}_`)&&!c)break;r=n}return r}function R(e,r,s){let c=new x().setFromObject(e,!0);if(c.isEmpty())return null;let n=s.getBoundingClientRect(),l=[];for(let p of[c.min.x,c.max.x])for(let d of[c.min.y,c.max.y])for(let b of[c.min.z,c.max.z])l.push(new P(p,d,b).project(r));let t=l.map(p=>n.left+(p.x+1)/2*n.width),a=l.map(p=>n.top+(1-p.y)/2*n.height),i=Math.max(n.left,Math.min(...t)),o=Math.min(n.right,Math.max(...t)),m=Math.max(n.top,Math.min(...a)),u=Math.min(n.bottom,Math.max(...a));return o<=i||u<=m?null:{left:i,top:m,width:o-i,height:u-m}}function O(e){let r=e.raycaster??new D,s=new T,c=t=>e.key?.(t)??v(t),n=(t,a)=>{let i=c(t);if(!i)return null;let o=R(t,e.camera,e.canvas);return o?{key:i,label:e.label?.(t)??S(t),sourceElement:e.canvas,bounds:o,context:f(t),data:{renderer:"Three.js",objectType:t.type,...t.name?{objectName:t.name}:{},scenePath:f(t),...a&&a!==t?{renderObjectName:a.name.trim()||a.type,renderObjectType:a.type,renderScenePath:f(a)}:{},position:h(t.position),rotation:h(t.rotation),scale:h(t.scale),visible:String(t.visible),...y(t)?{material:y(t)}:{},...Object.fromEntries(Object.entries(e.describe?.(t)??{}).filter(m=>typeof m[1]=="string"&&m[1].length>0))}}:null},l=t=>{let a=null;return e.scene.traverse(i=>{!a&&c(i)===t&&(a=i)}),a};return{id:e.id?.trim()||"three",hitTest({x:t,y:a}){let i=e.canvas.getBoundingClientRect();if(t<i.left||t>i.right||a<i.top||a>i.bottom)return null;s.set((t-i.left)/i.width*2-1,-((a-i.top)/i.height)*2+1),r.setFromCamera(s,e.camera);for(let o of r.intersectObject(e.scene,!0)){let m=e.select?e.select(o.object):F(o.object);if(!m||!m.visible)continue;let u=n(m,o.object);if(u)return u}return null},resolve(t){let a=l(t);return a?n(a):null},...e.captureFrame?{async captureSurfaces(){let t=await e.captureFrame?.();return t?[{element:e.canvas,dataUrl:t}]:[]}}:{}}}function w(e={}){let{registerSubjectAdapter:r}=g(),{gl:s,camera:c,scene:n}=M(),{root:l=n,captureFrame:t,describe:a,id:i,key:o,label:m,raycaster:u,select:p}=e,d=E(()=>O({id:i,canvas:s.domElement,camera:c,scene:l,raycaster:u,select:p,key:o,label:m,describe:b=>({framework:"@react-three/fiber",...a?.(b)}),...t===!1?{}:{captureFrame:t??(()=>j(s,n,c))}}),[c,t,a,s,i,o,m,u,l,n,p]);return C(()=>r(d),[d,r]),d}function U(e){return w(e),null}export{U as PopmeltThreeAdapter,w as usePopmeltThreeAdapter};
|
package/dist/adapter-three.d.mts
CHANGED
|
@@ -152,6 +152,8 @@ type PopmeltSubjectAdapter = {
|
|
|
152
152
|
};
|
|
153
153
|
|
|
154
154
|
type ThreeSubjectAdapterOptions = {
|
|
155
|
+
/** Unique adapter identity when a page owns more than one Three.js surface. */
|
|
156
|
+
id?: string;
|
|
155
157
|
canvas: HTMLCanvasElement;
|
|
156
158
|
camera: Camera;
|
|
157
159
|
scene: Object3D;
|
package/dist/adapter-three.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Box3 as y,Raycaster as x,Vector2 as O,Vector3 as j}from"three";function b(e){return[e.x,e.y,e.z].map(n=>Number(n.toFixed(4))).join(", ")}function
|
|
1
|
+
import{Box3 as y,Raycaster as x,Vector2 as O,Vector3 as j}from"three";function b(e){return[e.x,e.y,e.z].map(n=>Number(n.toFixed(4))).join(", ")}function d(e){let n=e.material;return n&&(Array.isArray(n)?n:[n]).map(r=>r.name?.trim()||r.type).filter(Boolean).join(", ")||void 0}function M(e,n,c){let s=e.domElement.width,r=e.domElement.height;if(s<=0||r<=0)return null;let l=e.getRenderTarget(),t=e.xr.enabled;try{return e.xr.enabled=!1,e.setRenderTarget(null),e.render(n,c),e.domElement.toDataURL("image/png")}catch{return null}finally{e.setRenderTarget(l),e.xr.enabled=t}}function D(e){let s=(e.parent?.children??[]).filter(t=>t.type===e.type&&t.name===e.name),r=Math.max(0,s.indexOf(e)),l=e.name.trim()||e.type;return`${encodeURIComponent(l)}[${r}]`}function f(e){let n=[],c=e;for(;c?.parent;)n.push(D(c)),c=c.parent;return n.reverse().join("/")}function v(e){let n=e.userData.popmeltId;return typeof n=="string"&&n.trim()?n.trim():f(e)}function T(e){let n=e.userData.popmeltLabel;return typeof n=="string"&&n.trim()?n.trim():e.name.trim()||e.type}function R(e){let n=e;for(;n.parent;){let c=n.name.trim(),s=c.match(/^(.*)_(?:alpha|normal|material)(?:_\d+)+$/i),r=n.parent;for(;r.parent&&!r.name.trim();)r=r.parent;let l=r.name.trim();if(!l||!c.startsWith(`${l}_`)&&!s)break;n=r}return n}function P(e,n,c){let s=new y().setFromObject(e,!0);if(s.isEmpty())return null;let r=c.getBoundingClientRect(),l=[];for(let p of[s.min.x,s.max.x])for(let h of[s.min.y,s.max.y])for(let g of[s.min.z,s.max.z])l.push(new j(p,h,g).project(n));let t=l.map(p=>r.left+(p.x+1)/2*r.width),a=l.map(p=>r.top+(1-p.y)/2*r.height),i=Math.max(r.left,Math.min(...t)),u=Math.min(r.right,Math.max(...t)),m=Math.max(r.top,Math.min(...a)),o=Math.min(r.bottom,Math.max(...a));return u<=i||o<=m?null:{left:i,top:m,width:u-i,height:o-m}}function C(e){let n=e.raycaster??new x,c=new O,s=t=>e.key?.(t)??v(t),r=(t,a)=>{let i=s(t);if(!i)return null;let u=P(t,e.camera,e.canvas);return u?{key:i,label:e.label?.(t)??T(t),sourceElement:e.canvas,bounds:u,context:f(t),data:{renderer:"Three.js",objectType:t.type,...t.name?{objectName:t.name}:{},scenePath:f(t),...a&&a!==t?{renderObjectName:a.name.trim()||a.type,renderObjectType:a.type,renderScenePath:f(a)}:{},position:b(t.position),rotation:b(t.rotation),scale:b(t.scale),visible:String(t.visible),...d(t)?{material:d(t)}:{},...Object.fromEntries(Object.entries(e.describe?.(t)??{}).filter(m=>typeof m[1]=="string"&&m[1].length>0))}}:null},l=t=>{let a=null;return e.scene.traverse(i=>{!a&&s(i)===t&&(a=i)}),a};return{id:e.id?.trim()||"three",hitTest({x:t,y:a}){let i=e.canvas.getBoundingClientRect();if(t<i.left||t>i.right||a<i.top||a>i.bottom)return null;c.set((t-i.left)/i.width*2-1,-((a-i.top)/i.height)*2+1),n.setFromCamera(c,e.camera);for(let u of n.intersectObject(e.scene,!0)){let m=e.select?e.select(u.object):R(u.object);if(!m||!m.visible)continue;let o=r(m,u.object);if(o)return o}return null},resolve(t){let a=l(t);return a?r(a):null},...e.captureFrame?{async captureSurfaces(){let t=await e.captureFrame?.();return t?[{element:e.canvas,dataUrl:t}]:[]}}:{}}}export{M as captureThreeRendererFrame,C as createThreeSubjectAdapter,R as selectThreeNamedPrimitiveParent,f as threeObjectPath};
|