@supersoniks/concorde 4.9.97-visual-stack.0 → 4.9.98-visual-stack.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.
Files changed (80) hide show
  1. package/build-infos.json +1 -1
  2. package/concorde-3d.bundle.js +143 -143
  3. package/concorde-3d.es.js +1393 -1377
  4. package/concorde-core.bundle.js +1 -1
  5. package/concorde-core.es.js +1 -1
  6. package/concorde-hugging-face-infer.bundle.js +1 -1
  7. package/concorde-hugging-face-infer.es.js +1 -1
  8. package/concorde-shader.bundle.js +19 -19
  9. package/concorde-shader.es.js +2317 -2172
  10. package/concorde-webgpu.bundle.js +30 -30
  11. package/concorde-webgpu.es.js +2439 -2346
  12. package/dist/concorde-3d.bundle.js +143 -143
  13. package/dist/concorde-3d.es.js +1393 -1377
  14. package/dist/concorde-core.bundle.js +1 -1
  15. package/dist/concorde-core.es.js +1 -1
  16. package/dist/concorde-hugging-face-infer.bundle.js +1 -1
  17. package/dist/concorde-hugging-face-infer.es.js +1 -1
  18. package/dist/concorde-shader.bundle.js +19 -19
  19. package/dist/concorde-shader.es.js +2317 -2172
  20. package/dist/concorde-webgpu.bundle.js +30 -30
  21. package/dist/concorde-webgpu.es.js +2439 -2346
  22. package/dist/js/core/components/functional/3d/3d.js +11 -1
  23. package/dist/js/core/components/functional/3d/3d.js.map +1 -1
  24. package/dist/js/core/components/functional/3d/constants.js +2 -0
  25. package/dist/js/core/components/functional/3d/constants.js.map +1 -1
  26. package/dist/js/core/components/functional/3d/frame-source.js +22 -0
  27. package/dist/js/core/components/functional/3d/frame-source.js.map +1 -0
  28. package/dist/js/core/components/functional/3d/reload.js +3 -0
  29. package/dist/js/core/components/functional/3d/reload.js.map +1 -1
  30. package/dist/js/core/components/functional/shader/gl-runtime.js +152 -17
  31. package/dist/js/core/components/functional/shader/gl-runtime.js.map +1 -1
  32. package/dist/js/core/components/functional/shader/shader.js +55 -6
  33. package/dist/js/core/components/functional/shader/shader.js.map +1 -1
  34. package/dist/js/core/components/functional/shader/types.js.map +1 -1
  35. package/dist/js/core/components/functional/webgpu/webgpu.js +9 -0
  36. package/dist/js/core/components/functional/webgpu/webgpu.js.map +1 -1
  37. package/dist/js/core/utils/mediaRef.js +49 -0
  38. package/dist/js/core/utils/mediaRef.js.map +1 -1
  39. package/dist/types/core/components/functional/3d/3d.d.ts +7 -2
  40. package/dist/types/core/components/functional/3d/3d.d.ts.map +1 -1
  41. package/dist/types/core/components/functional/3d/constants.d.ts +1 -1
  42. package/dist/types/core/components/functional/3d/constants.d.ts.map +1 -1
  43. package/dist/types/core/components/functional/3d/frame-source.d.ts +23 -0
  44. package/dist/types/core/components/functional/3d/frame-source.d.ts.map +1 -0
  45. package/dist/types/core/components/functional/3d/reload.d.ts +3 -0
  46. package/dist/types/core/components/functional/3d/reload.d.ts.map +1 -1
  47. package/dist/types/core/components/functional/3d/types.d.ts +7 -0
  48. package/dist/types/core/components/functional/3d/types.d.ts.map +1 -1
  49. package/dist/types/core/components/functional/shader/gl-runtime.d.ts +20 -1
  50. package/dist/types/core/components/functional/shader/gl-runtime.d.ts.map +1 -1
  51. package/dist/types/core/components/functional/shader/shader.d.ts +14 -3
  52. package/dist/types/core/components/functional/shader/shader.d.ts.map +1 -1
  53. package/dist/types/core/components/functional/shader/types.d.ts +6 -0
  54. package/dist/types/core/components/functional/shader/types.d.ts.map +1 -1
  55. package/dist/types/core/components/functional/webgpu/webgpu.d.ts +4 -0
  56. package/dist/types/core/components/functional/webgpu/webgpu.d.ts.map +1 -1
  57. package/dist/types/core/utils/mediaRef.d.ts +19 -0
  58. package/dist/types/core/utils/mediaRef.d.ts.map +1 -1
  59. package/package.json +13 -1
  60. package/src/core/components/functional/3d/3d.md +12 -2
  61. package/src/core/components/functional/3d/3d.ts +12 -1
  62. package/src/core/components/functional/3d/constants.ts +2 -0
  63. package/src/core/components/functional/3d/frame-source.ts +30 -0
  64. package/src/core/components/functional/3d/reload.ts +6 -0
  65. package/src/core/components/functional/3d/types.ts +5 -0
  66. package/src/core/components/functional/shader/gl-runtime.ts +205 -24
  67. package/src/core/components/functional/shader/shader.md +10 -8
  68. package/src/core/components/functional/shader/shader.spec.ts +83 -3
  69. package/src/core/components/functional/shader/shader.ts +61 -6
  70. package/src/core/components/functional/shader/types.ts +3 -1
  71. package/src/core/components/functional/webgpu/webgpu.ts +9 -0
  72. package/src/core/utils/mediaRef.spec.ts +36 -0
  73. package/src/core/utils/mediaRef.ts +63 -0
  74. package/src/docs/_misc/visual-stack.md +18 -2
  75. package/src/docs/components/docs-demo-sources.ts +14 -0
  76. package/src/docs/docs.ts +1 -0
  77. package/src/docs/example/docs-3d-shader-live-demo.ts +98 -0
  78. package/src/docs/search/docs-search.json +2347 -877
  79. package/src/tsconfig.json +9 -0
  80. package/src/tsconfig.tsbuildinfo +1 -1
@@ -2,7 +2,10 @@ import { describe, expect, it, vi, beforeEach } from "vitest";
2
2
  import {
3
3
  attachMediaUrls,
4
4
  cloneMediaRef,
5
+ isFrameSource,
5
6
  isMediaBlobObject,
7
+ mediaElementKey,
8
+ registerLiveElement,
6
9
  revokeMediaUrls,
7
10
  toMediaUrl,
8
11
  } from "./mediaRef";
@@ -15,6 +18,39 @@ describe("toMediaUrl", () => {
15
18
  expect(toMediaUrl(null)).toBeNull();
16
19
  expect(toMediaUrl({ blob: new Blob() })).toBeNull();
17
20
  });
21
+
22
+ it("ignore element (pas d’URL)", () => {
23
+ expect(toMediaUrl({ element: "#plateau" })).toBeNull();
24
+ });
25
+ });
26
+
27
+ describe("isFrameSource / mediaElementKey", () => {
28
+ it("détecte SonicFrameSource", () => {
29
+ expect(
30
+ isFrameSource({
31
+ getFrameCanvas: () => null,
32
+ frameSeq: 0,
33
+ }),
34
+ ).toBe(true);
35
+ expect(isFrameSource({})).toBe(false);
36
+ expect(isFrameSource(null)).toBe(false);
37
+ });
38
+
39
+ it("normalise element string / Element avec id", () => {
40
+ expect(mediaElementKey("#plateau")).toBe("#plateau");
41
+ expect(mediaElementKey("plateau")).toBe("#plateau");
42
+ expect(mediaElementKey("")).toBeNull();
43
+ const el = document.createElement("div");
44
+ el.id = "scene";
45
+ expect(mediaElementKey(el)).toBe("#scene");
46
+ });
47
+
48
+ it("enregistre un Element sans id", () => {
49
+ const el = document.createElement("div");
50
+ const key = registerLiveElement(el);
51
+ expect(key.startsWith("#__sonic_frame_")).toBe(true);
52
+ expect(mediaElementKey(el)).toBe(key);
53
+ });
18
54
  });
19
55
 
20
56
  describe("attachMediaUrls / revokeMediaUrls", () => {
@@ -4,6 +4,7 @@
4
4
  * - `url` : http(s) | blob: | data: (préféré pour les canaux shader)
5
5
  * - `blob` : binaire (HF, upload) — le producteur publie aussi `url` quand possible
6
6
  * - `blobUrl` : alias historique (extract shader)
7
+ * - `element` : sélecteur `#id` ou Element (pont live → canaux shader, ignoré par toMediaUrl)
7
8
  */
8
9
 
9
10
  export type SonicMediaRef = {
@@ -13,8 +14,70 @@ export type SonicMediaRef = {
13
14
  width?: number;
14
15
  height?: number;
15
16
  mime?: string;
17
+ /** Sélecteur `#id` ou référence Element (upload live, pas d’URL). */
18
+ element?: string | Element;
16
19
  };
17
20
 
21
+ /**
22
+ * Contrat minimal pour qu’un composant Concorde alimente un canal shader
23
+ * sans JPEG / blob (`channel0="#plateau"` ou `{ element }`).
24
+ */
25
+ export type SonicFrameSource = {
26
+ /** Canvas lisible (preserveDrawingBuffer ou 2D). `null` tant que pas prêt. */
27
+ getFrameCanvas(): HTMLCanvasElement | null;
28
+ /** Incrémenté après chaque rendu effectif. */
29
+ readonly frameSeq: number;
30
+ };
31
+
32
+ export function isFrameSource(el: unknown): el is SonicFrameSource {
33
+ if (!el || typeof el !== "object") return false;
34
+ const o = el as SonicFrameSource;
35
+ return (
36
+ typeof o.getFrameCanvas === "function" && typeof o.frameSeq === "number"
37
+ );
38
+ }
39
+
40
+ /** Clés synthétiques pour Elements DP sans `id` (`#__sonic_frame_N`). */
41
+ const LIVE_PREFIX = "#__sonic_frame_";
42
+ let liveSeq = 0;
43
+ const liveByKey = new Map<string, Element>();
44
+ const keyByLive = new WeakMap<Element, string>();
45
+
46
+ /** Enregistre un Element sans id → clé `#__sonic_frame_N` (réutilisée). */
47
+ export function registerLiveElement(el: Element): string {
48
+ const existing = keyByLive.get(el);
49
+ if (existing) return existing;
50
+ const key = `${LIVE_PREFIX}${++liveSeq}`;
51
+ liveByKey.set(key, el);
52
+ keyByLive.set(el, key);
53
+ return key;
54
+ }
55
+
56
+ export function lookupLiveElement(key: string): Element | null {
57
+ if (!key.startsWith(LIVE_PREFIX)) return null;
58
+ const el = liveByKey.get(key) ?? null;
59
+ if (el && !el.isConnected) {
60
+ liveByKey.delete(key);
61
+ return null;
62
+ }
63
+ return el;
64
+ }
65
+
66
+ /** Normalise `element` DP → clé canal (`#id` ou live). */
67
+ export function mediaElementKey(value: unknown): string | null {
68
+ if (value == null) return null;
69
+ if (typeof value === "string") {
70
+ const s = value.trim();
71
+ if (!s) return null;
72
+ return s.startsWith("#") ? s : `#${s}`;
73
+ }
74
+ if (typeof Element !== "undefined" && value instanceof Element) {
75
+ if (value.id) return `#${value.id}`;
76
+ return registerLiveElement(value);
77
+ }
78
+ return null;
79
+ }
80
+
18
81
  /** Objet image sérialisé (sortie HF / extract) : Blob + dimensions. */
19
82
  export function isMediaBlobObject(
20
83
  value: unknown,
@@ -1,6 +1,6 @@
1
1
  # Visual stack
2
2
 
3
- Examples of chaining opt-in addons (HF, shader, WebGPU). Outside the main “functional” flow.
3
+ Examples of chaining opt-in addons (HF, shader, WebGPU, 3D). Outside the main “functional” flow.
4
4
 
5
5
  ## HF depth → parallax
6
6
 
@@ -29,6 +29,21 @@ photo (sample)
29
29
 
30
30
  <docs-lit-demo for="docs-visual-stack-demo"></docs-lit-demo>
31
31
 
32
+ ## 3D → shader live (GPU bridge)
33
+
34
+ `sonic-3d` and `sonic-shader` keep separate WebGL contexts. For realtime post, point a channel at the 3D host with `#id` — the shader copies the canvas each frame (`texImage2D`), no JPEG.
35
+
36
+ ```html
37
+ <sonic-3d id="plateau" play auto-rotate …></sonic-3d>
38
+ <sonic-shader channel0="#plateau" image="…" play></sonic-shader>
39
+ ```
40
+
41
+ Also accepted: `<img>`, `<video>`, `<canvas>`, or another Concorde host that implements `SonicFrameSource` (`getFrameCanvas` + `frameSeq`). DP form: `{ element: "#plateau" }` or `{ element: el }`.
42
+
43
+ `frame-out` (JPEG ObjectURL) remains for export / HF / freeze — not for live post.
44
+
45
+ <docs-lit-demo for="docs-3d-shader-live-demo"></docs-lit-demo>
46
+
32
47
  ## Harris → patches → WebGPU
33
48
 
34
49
  `sonic-shader` detects corners (Harris) and extracts patches → `channel0…3` on `sonic-webgpu` (`kernel="image"`): GPU mosaic.
@@ -41,9 +56,10 @@ photo (sample)
41
56
  |------|-----|
42
57
  | Depth | [Hugging Face infer](#core/components/functional/infer/hugging-face/hugging-face-infer.md/hugging-face-infer) |
43
58
  | FX + extract | [Shader](#core/components/functional/shader/shader.md/shader) |
59
+ | 3D viewer | [3D](#core/components/functional/3d/3d.md/3d) |
44
60
  | Compute / mosaic | [WebGPU](#core/components/functional/webgpu/webgpu.md/webgpu) |
45
61
  | Stats / thresholds | [Jsonata](#core/components/functional/jsonata/jsonata.md/jsonata) |
46
62
 
47
63
  ## Media contract
48
64
 
49
- `SonicMediaRef` / `toMediaUrl` / `cloneMediaRef` — `@supersoniks/concorde/core/utils/mediaRef`.
65
+ `SonicMediaRef` / `SonicFrameSource` / `toMediaUrl` / `cloneMediaRef` — `@supersoniks/concorde/core/utils/mediaRef`.
@@ -215,6 +215,14 @@ export const DOCS_LIT_DEMO_REGISTRY: Record<string, DocsLitDemoConfig> = {
215
215
  },
216
216
  ],
217
217
  },
218
+ "docs-3d-shader-live-demo": {
219
+ sources: [
220
+ {
221
+ path: "src/docs/example/docs-3d-shader-live-demo.ts",
222
+ label: "3D → shader live",
223
+ },
224
+ ],
225
+ },
218
226
  "docs-webgpu-demo": {
219
227
  sources: [
220
228
  {
@@ -492,6 +500,12 @@ export const DOCS_DEMO_SOURCE_REGISTRY: Record<string, DocsSource[]> = {
492
500
  "docs-visual-stack-demo": [
493
501
  { path: "src/docs/example/docs-visual-stack-demo.ts", label: "visual stack" },
494
502
  ],
503
+ "docs-3d-shader-live-demo": [
504
+ {
505
+ path: "src/docs/example/docs-3d-shader-live-demo.ts",
506
+ label: "3d → shader live",
507
+ },
508
+ ],
495
509
  "docs-webgpu-demo": [
496
510
  { path: "src/docs/example/docs-webgpu-demo.ts", label: "webgpu demo" },
497
511
  ],
package/src/docs/docs.ts CHANGED
@@ -21,6 +21,7 @@ import "./example/docs-hugging-face-demos";
21
21
  import "./example/docs-shader-demos";
22
22
  import "./example/docs-webgpu-demo";
23
23
  import "./example/docs-visual-stack-demo";
24
+ import "./example/docs-3d-shader-live-demo";
24
25
  import "./example/docs-harris-webgpu-demo";
25
26
  import "./example/docs-router-demos";
26
27
  import "./example/docs-submit-demos";
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Démo pont live : sonic-3d → sonic-shader via channel0="#plateau"
3
+ * (copie canvas chaque frame, sans JPEG frame-out).
4
+ */
5
+ import { css, html, LitElement } from "lit";
6
+ import { customElement } from "lit/decorators.js";
7
+ import { tailwind } from "../tailwind";
8
+ import "../../core/components/functional/3d/3d";
9
+ import "../../core/components/functional/shader/shader";
10
+ import { DEMO_3D_STYLES, HELMET_GLB } from "./docs-3d-shared";
11
+
12
+ /** Aberration chromatique + bords neon — bien visible vs le 3d brut. */
13
+ const LIVE_POST = `
14
+ void mainImage(out vec4 fragColor, in vec2 fragCoord) {
15
+ vec2 uv = fragCoord / iResolution.xy;
16
+ vec2 c = uv - 0.5;
17
+ float aber = 0.004 + clamp(uParam0, 0.0, 1.0) * 0.028;
18
+ aber *= 1.0 + 0.35 * sin(iTime * 2.2);
19
+
20
+ float r = texture(iChannel0, uv + c * aber).r;
21
+ float g = texture(iChannel0, uv).g;
22
+ float b = texture(iChannel0, uv - c * aber).b;
23
+ vec3 col = vec3(r, g, b);
24
+
25
+ // Contours sobel légers (luma)
26
+ vec2 px = 1.0 / max(iResolution.xy, vec2(1.0));
27
+ float tl = dot(texture(iChannel0, uv + px * vec2(-1.0, 1.0)).rgb, vec3(0.299, 0.587, 0.114));
28
+ float tr = dot(texture(iChannel0, uv + px * vec2( 1.0, 1.0)).rgb, vec3(0.299, 0.587, 0.114));
29
+ float bl = dot(texture(iChannel0, uv + px * vec2(-1.0, -1.0)).rgb, vec3(0.299, 0.587, 0.114));
30
+ float br = dot(texture(iChannel0, uv + px * vec2( 1.0, -1.0)).rgb, vec3(0.299, 0.587, 0.114));
31
+ float edge = length(vec2(tr + br - tl - bl, tl + tr - bl - br));
32
+ col += vec3(0.15, 0.85, 1.0) * smoothstep(0.08, 0.45, edge);
33
+
34
+ // Scanlines + vignette
35
+ col *= 0.88 + 0.12 * sin(uv.y * iResolution.y * 1.2);
36
+ float vig = smoothstep(1.15, 0.35, length(c));
37
+ col *= vig;
38
+
39
+ fragColor = vec4(col, 1.0);
40
+ }
41
+ `;
42
+
43
+ @customElement("docs-3d-shader-live-demo")
44
+ export class Docs3dShaderLiveDemo extends LitElement {
45
+ static styles = [
46
+ tailwind,
47
+ DEMO_3D_STYLES,
48
+ css`
49
+ .grid {
50
+ display: grid;
51
+ gap: 0.75rem;
52
+ grid-template-columns: 1fr;
53
+ }
54
+ @media (min-width: 720px) {
55
+ .grid {
56
+ grid-template-columns: 1fr 1fr;
57
+ }
58
+ }
59
+ sonic-3d,
60
+ sonic-shader {
61
+ width: 100%;
62
+ border-radius: 0.5rem;
63
+ overflow: hidden;
64
+ }
65
+ `,
66
+ ];
67
+
68
+ render() {
69
+ return html`
70
+ <div class="flex flex-col gap-2">
71
+ <div class="grid">
72
+ <sonic-3d
73
+ id="plateau"
74
+ src=${HELMET_GLB}
75
+ camera="orbit"
76
+ auto-rotate
77
+ play
78
+ min-distance="1"
79
+ max-distance="10"
80
+ aspect-ratio="16/10"
81
+ ></sonic-3d>
82
+ <sonic-shader
83
+ play
84
+ channel0="#plateau"
85
+ image=${LIVE_POST}
86
+ param0="0.7"
87
+ aspect-ratio="16/10"
88
+ ></sonic-shader>
89
+ </div>
90
+ <p class="text-sm text-neutral-500">
91
+ Live bridge: <code>channel0="#plateau"</code> (no JPEG). Left = raw
92
+ <code>sonic-3d</code>, right = chromatic aberration + neon edges +
93
+ scanlines. Slider-ready via <code>param0</code> (aberration strength).
94
+ </p>
95
+ </div>
96
+ `;
97
+ }
98
+ }