@nadicodeai/ui 0.22.0 → 1.0.1
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/AGENTS.md +4 -4
- package/LICENSES/PAPER-SHADERS-APACHE-2.0.txt +186 -0
- package/NOTICE +12 -0
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +1 -0
- package/dist/components/agent-card.d.ts +13 -0
- package/dist/components/agent-card.d.ts.map +1 -0
- package/dist/components/agent-card.js +15 -0
- package/dist/components/agent-visual.d.ts +17 -0
- package/dist/components/agent-visual.d.ts.map +1 -0
- package/dist/components/agent-visual.js +63 -0
- package/dist/components/alert-dialog.js +1 -1
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/badge.d.ts.map +1 -1
- package/dist/components/badge.js +9 -0
- package/dist/components/card.d.ts +5 -3
- package/dist/components/card.d.ts.map +1 -1
- package/dist/components/card.js +7 -7
- package/dist/components/chart.js +1 -1
- package/dist/components/combobox.js +1 -1
- package/dist/components/context-menu.js +1 -1
- package/dist/components/dialog.js +1 -1
- package/dist/components/drawer.js +1 -1
- package/dist/components/dropdown-menu.js +1 -1
- package/dist/components/empty.d.ts +5 -2
- package/dist/components/empty.d.ts.map +1 -1
- package/dist/components/empty.js +3 -3
- package/dist/components/feedback-state.js +1 -1
- package/dist/components/glass-control.d.ts +7 -0
- package/dist/components/glass-control.d.ts.map +1 -0
- package/dist/components/glass-control.js +14 -0
- package/dist/components/hover-card.js +1 -1
- package/dist/components/label-system.d.ts +1 -10
- package/dist/components/label-system.d.ts.map +1 -1
- package/dist/components/label-system.js +1 -7
- package/dist/components/live-demo.js +1 -1
- package/dist/components/menubar.js +1 -1
- package/dist/components/nav-bar.d.ts +6 -8
- package/dist/components/nav-bar.d.ts.map +1 -1
- package/dist/components/nav-bar.js +8 -9
- package/dist/components/navigation-menu.js +2 -2
- package/dist/components/popover.js +1 -1
- package/dist/components/select.js +1 -1
- package/dist/components/sheet.js +1 -1
- package/dist/components/sidebar.js +1 -1
- package/dist/components/sonner.js +2 -2
- package/dist/components/testimonials.d.ts +1 -1
- package/dist/components/testimonials.js +2 -2
- package/dist/components/tooltip.js +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/internal/agent-visual/color.d.ts +4 -0
- package/dist/internal/agent-visual/color.d.ts.map +1 -0
- package/dist/internal/agent-visual/color.js +72 -0
- package/dist/internal/agent-visual/poster.d.ts +6 -0
- package/dist/internal/agent-visual/poster.d.ts.map +1 -0
- package/dist/internal/agent-visual/poster.js +35 -0
- package/dist/internal/agent-visual/recipes.d.ts +15 -0
- package/dist/internal/agent-visual/recipes.d.ts.map +1 -0
- package/dist/internal/agent-visual/recipes.js +72 -0
- package/dist/internal/agent-visual/renderer.d.ts +10 -0
- package/dist/internal/agent-visual/renderer.d.ts.map +1 -0
- package/dist/internal/agent-visual/renderer.js +112 -0
- package/dist/internal/agent-visual/shader.d.ts +2 -0
- package/dist/internal/agent-visual/shader.d.ts.map +1 -0
- package/dist/internal/agent-visual/shader.js +158 -0
- package/dist/internal/assistant-ui/thread.js +3 -3
- package/dist/styles/globals.css +21 -0
- package/docs/agents/nadicodeai-ui.md +4 -2
- package/docs/consuming-cross-repo.md +3 -1
- package/docs/contract.md +80 -2
- package/docs/migration/1.0.0.md +75 -0
- package/llms.txt +2 -0
- package/package.json +10 -4
- package/skills/nadicodeai-ui/SKILL.md +7 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export const AGENT_VISUAL_RECIPE_SPECS = {
|
|
2
|
+
general: {
|
|
3
|
+
colors: ["cobalto", "verde", "arancio", "giallo", "rosso"],
|
|
4
|
+
count: 10,
|
|
5
|
+
frame: 0,
|
|
6
|
+
material: "solid",
|
|
7
|
+
posterForm: [
|
|
8
|
+
[45, 64, 29],
|
|
9
|
+
[68, 42, 32],
|
|
10
|
+
[99, 45, 34],
|
|
11
|
+
[116, 71, 27],
|
|
12
|
+
[79, 80, 35],
|
|
13
|
+
],
|
|
14
|
+
size: 0.83,
|
|
15
|
+
},
|
|
16
|
+
reasoning: {
|
|
17
|
+
colors: ["cobalto", "verde", "giallo"],
|
|
18
|
+
count: 10,
|
|
19
|
+
frame: 0,
|
|
20
|
+
material: "points",
|
|
21
|
+
posterForm: [
|
|
22
|
+
[44, 61, 28],
|
|
23
|
+
[69, 39, 31],
|
|
24
|
+
[98, 44, 34],
|
|
25
|
+
[113, 71, 29],
|
|
26
|
+
[76, 80, 34],
|
|
27
|
+
],
|
|
28
|
+
size: 0.83,
|
|
29
|
+
},
|
|
30
|
+
coordination: {
|
|
31
|
+
colors: ["verde", "cobalto", "arancio"],
|
|
32
|
+
count: 8,
|
|
33
|
+
frame: 2_700,
|
|
34
|
+
material: "wire",
|
|
35
|
+
posterForm: [
|
|
36
|
+
[48, 61, 31],
|
|
37
|
+
[77, 40, 33],
|
|
38
|
+
[111, 58, 29],
|
|
39
|
+
[90, 82, 27],
|
|
40
|
+
],
|
|
41
|
+
size: 0.76,
|
|
42
|
+
},
|
|
43
|
+
communication: {
|
|
44
|
+
colors: ["giallo", "arancio", "rosso"],
|
|
45
|
+
count: 12,
|
|
46
|
+
frame: 5_400,
|
|
47
|
+
material: "solid",
|
|
48
|
+
posterForm: [
|
|
49
|
+
[51, 55, 29],
|
|
50
|
+
[79, 43, 35],
|
|
51
|
+
[107, 63, 30],
|
|
52
|
+
[77, 80, 28],
|
|
53
|
+
],
|
|
54
|
+
size: 0.69,
|
|
55
|
+
},
|
|
56
|
+
execution: {
|
|
57
|
+
colors: ["rosso", "arancio", "cobalto"],
|
|
58
|
+
count: 6,
|
|
59
|
+
frame: 8_100,
|
|
60
|
+
material: "particles",
|
|
61
|
+
posterForm: [
|
|
62
|
+
[48, 65, 28],
|
|
63
|
+
[78, 52, 39],
|
|
64
|
+
[109, 64, 32],
|
|
65
|
+
[82, 86, 24],
|
|
66
|
+
],
|
|
67
|
+
size: 0.92,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
export function campoVariable(campo) {
|
|
71
|
+
return `--nc-campo-${campo}`;
|
|
72
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type AgentVisualRecipe } from "./recipes";
|
|
2
|
+
type AgentVisualRendererProps = {
|
|
3
|
+
host: HTMLElement;
|
|
4
|
+
onReady: () => void;
|
|
5
|
+
onUnavailable: () => void;
|
|
6
|
+
recipe: AgentVisualRecipe;
|
|
7
|
+
};
|
|
8
|
+
export default function AgentVisualRenderer({ host, onReady, onUnavailable, recipe, }: AgentVisualRendererProps): import("react").JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/internal/agent-visual/renderer.tsx"],"names":[],"mappings":"AAYA,OAAO,EAA4C,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAU7F,KAAK,wBAAwB,GAAG;IAC9B,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,MAAM,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EAC1C,IAAI,EACJ,OAAO,EACP,aAAa,EACb,MAAM,GACP,EAAE,wBAAwB,+BA8G1B"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { defaultObjectSizing, getShaderNoiseTexture, metaballsFragmentShader, ShaderFitOptions, ShaderMount as PaperShaderMount, } from "@paper-design/shaders";
|
|
4
|
+
import { useEffect, useRef } from "react";
|
|
5
|
+
import { resolveCampoColor } from "./color.js";
|
|
6
|
+
import { AGENT_VISUAL_RECIPE_SPECS, campoVariable } from "./recipes.js";
|
|
7
|
+
import { AGENT_VISUAL_SHADER } from "./shader.js";
|
|
8
|
+
const MATERIAL_INDEX = {
|
|
9
|
+
particles: 3,
|
|
10
|
+
points: 1,
|
|
11
|
+
solid: 0,
|
|
12
|
+
wire: 2,
|
|
13
|
+
};
|
|
14
|
+
export default function AgentVisualRenderer({ host, onReady, onUnavailable, recipe, }) {
|
|
15
|
+
const mountRef = useRef(null);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const mount = mountRef.current;
|
|
18
|
+
if (!mount)
|
|
19
|
+
return;
|
|
20
|
+
const spec = AGENT_VISUAL_RECIPE_SPECS[recipe];
|
|
21
|
+
const isSolid = spec.material === "solid";
|
|
22
|
+
const colors = spec.colors.map((color) => resolveCampoColor(host, campoVariable(color)));
|
|
23
|
+
const colorBack = resolveCampoColor(host, campoVariable("inchiostro"));
|
|
24
|
+
const hasPalette = colors.every((color) => color !== null) && colorBack !== null;
|
|
25
|
+
if (!hasPalette) {
|
|
26
|
+
onUnavailable();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
let cancelled = false;
|
|
30
|
+
let canvas = null;
|
|
31
|
+
let readyFrame = 0;
|
|
32
|
+
let shaderMount = null;
|
|
33
|
+
const clearMount = () => {
|
|
34
|
+
mount.replaceChildren();
|
|
35
|
+
mount.removeAttribute("data-paper-shader");
|
|
36
|
+
};
|
|
37
|
+
const disposeMount = () => {
|
|
38
|
+
try {
|
|
39
|
+
shaderMount?.dispose();
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// The deterministic poster remains visible even if vendor cleanup fails.
|
|
43
|
+
}
|
|
44
|
+
shaderMount = null;
|
|
45
|
+
clearMount();
|
|
46
|
+
};
|
|
47
|
+
const handleContextLost = (event) => {
|
|
48
|
+
event.preventDefault();
|
|
49
|
+
cancelled = true;
|
|
50
|
+
cancelAnimationFrame(readyFrame);
|
|
51
|
+
readyFrame = 0;
|
|
52
|
+
canvas?.removeEventListener("webglcontextlost", handleContextLost);
|
|
53
|
+
canvas = null;
|
|
54
|
+
disposeMount();
|
|
55
|
+
onUnavailable();
|
|
56
|
+
};
|
|
57
|
+
const initialize = async () => {
|
|
58
|
+
try {
|
|
59
|
+
const noiseTexture = getShaderNoiseTexture();
|
|
60
|
+
if (noiseTexture && !noiseTexture.complete)
|
|
61
|
+
await noiseTexture.decode();
|
|
62
|
+
if (cancelled)
|
|
63
|
+
return;
|
|
64
|
+
shaderMount = new PaperShaderMount(mount, isSolid ? metaballsFragmentShader : AGENT_VISUAL_SHADER, {
|
|
65
|
+
u_colorBack: colorBack,
|
|
66
|
+
u_colors: colors,
|
|
67
|
+
u_colorsCount: colors.length,
|
|
68
|
+
u_count: spec.count,
|
|
69
|
+
u_fit: ShaderFitOptions[defaultObjectSizing.fit],
|
|
70
|
+
u_noiseTexture: noiseTexture,
|
|
71
|
+
u_offsetX: defaultObjectSizing.offsetX,
|
|
72
|
+
u_offsetY: defaultObjectSizing.offsetY,
|
|
73
|
+
u_originX: defaultObjectSizing.originX,
|
|
74
|
+
u_originY: defaultObjectSizing.originY,
|
|
75
|
+
u_rotation: defaultObjectSizing.rotation,
|
|
76
|
+
u_scale: 1.15,
|
|
77
|
+
u_size: spec.size,
|
|
78
|
+
u_worldHeight: defaultObjectSizing.worldHeight,
|
|
79
|
+
u_worldWidth: defaultObjectSizing.worldWidth,
|
|
80
|
+
...(isSolid
|
|
81
|
+
? {}
|
|
82
|
+
: {
|
|
83
|
+
u_detail: 0.55,
|
|
84
|
+
u_material: MATERIAL_INDEX[spec.material],
|
|
85
|
+
}),
|
|
86
|
+
}, undefined, 0.24, spec.frame, undefined, 720_000);
|
|
87
|
+
canvas = shaderMount.canvasElement;
|
|
88
|
+
canvas.addEventListener("webglcontextlost", handleContextLost);
|
|
89
|
+
readyFrame = requestAnimationFrame(() => {
|
|
90
|
+
readyFrame = 0;
|
|
91
|
+
if (!cancelled)
|
|
92
|
+
onReady();
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
canvas?.removeEventListener("webglcontextlost", handleContextLost);
|
|
97
|
+
canvas = null;
|
|
98
|
+
disposeMount();
|
|
99
|
+
if (!cancelled)
|
|
100
|
+
onUnavailable();
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
void initialize();
|
|
104
|
+
return () => {
|
|
105
|
+
cancelled = true;
|
|
106
|
+
cancelAnimationFrame(readyFrame);
|
|
107
|
+
canvas?.removeEventListener("webglcontextlost", handleContextLost);
|
|
108
|
+
disposeMount();
|
|
109
|
+
};
|
|
110
|
+
}, [host, onReady, onUnavailable, recipe]);
|
|
111
|
+
return _jsx("div", { className: "size-full", ref: mountRef });
|
|
112
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const AGENT_VISUAL_SHADER = "#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform sampler2D u_noiseTexture;\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[8];\nuniform float u_colorsCount;\nuniform float u_size;\nuniform float u_count;\nuniform float u_material;\nuniform float u_detail;\nuniform vec2 u_resolution;\n\nin vec2 v_objectUV;\nout vec4 fragColor;\n\n#define TWO_PI 6.28318530718\n\nfloat randomR(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).r;\n}\n\nfloat noise(float x) {\n float i = floor(x);\n float f = fract(x);\n float u = f * f * (3.0 - 2.0 * f);\n return mix(randomR(vec2(i, 0.0)), randomR(vec2(i + 1.0, 0.0)), u);\n}\n\nfloat getBallShape(vec2 uv, vec2 c, float p) {\n float s = .5 * length(uv - c);\n s = 1. - clamp(s, 0., 1.);\n return pow(s, p);\n}\n\nfloat hash21(vec2 p) {\n p = fract(p * vec2(123.34, 456.21));\n p += dot(p, p + 45.32);\n return fract(p.x * p.y);\n}\n\nfloat orderedPoints(vec2 surfaceUV, float depth) {\n float density = clamp(min(u_resolution.x, u_resolution.y) / 12.0 * u_detail, 6.0, 34.0);\n vec2 pointUV = fract(surfaceUV * density) - 0.5;\n float radius = mix(0.14, 0.23, depth);\n return 1.0 - smoothstep(radius * 0.7, radius, length(pointUV));\n}\n\nfloat triangularWire(vec2 surfaceUV, float depth) {\n float density = clamp(min(u_resolution.x, u_resolution.y) / 16.0 * u_detail, 5.0, 26.0);\n vec2 grid = surfaceUV * density;\n float horizontal = abs(fract(grid.y) - 0.5);\n float diagonalA = abs(fract(grid.x + grid.y * 0.5) - 0.5);\n float diagonalB = abs(fract(grid.x - grid.y * 0.5) - 0.5);\n float nearestLine = min(horizontal, min(diagonalA, diagonalB));\n float width = mix(0.032, 0.072, depth);\n return 1.0 - smoothstep(width * 0.55, width, nearestLine);\n}\n\nfloat particleLayer(vec2 surfaceUV, float density, float depth, float time, float layerSeed, float threshold) {\n vec2 gridUV = surfaceUV * density + layerSeed;\n vec2 cell = floor(gridUV);\n vec2 local = fract(gridUV) - 0.5;\n float seed = hash21(cell + layerSeed);\n vec2 jitter = vec2(hash21(cell + layerSeed + 3.17), hash21(cell + layerSeed + 8.41)) - 0.5;\n jitter *= 0.72;\n jitter += 0.08 * vec2(sin(time * 0.42 + seed * 18.0 + layerSeed), cos(time * 0.31 + seed * 14.0 - layerSeed));\n float radius = mix(0.055, 0.175, hash21(cell + layerSeed + 14.3)) * mix(0.78, 1.35, depth);\n float particle = 1.0 - smoothstep(radius * 0.68, radius, length(local - jitter));\n float brightness = mix(0.45, 1.0, hash21(cell + layerSeed + 24.7));\n return particle * step(threshold, seed) * brightness;\n}\n\nfloat livingParticles(vec2 surfaceUV, float depth, float time) {\n float density = clamp(min(u_resolution.x, u_resolution.y) / 6.5 * u_detail, 13.0, 68.0);\n float dust = particleLayer(surfaceUV, density, depth, time, 0.0, 0.16);\n float motes = particleLayer(surfaceUV, density * 0.46, depth, time * 0.72, 19.7, 0.62);\n return max(dust * 0.78, motes);\n}\n\nfloat surfacePattern(vec2 surfaceUV, float depth, float material, float time) {\n if (material < 0.5) return 1.0;\n if (material < 1.5) return orderedPoints(surfaceUV, depth);\n if (material < 2.5) return triangularWire(surfaceUV, depth);\n return livingParticles(surfaceUV, depth, time);\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV + .5;\n const float firstFrameOffset = 2503.4;\n float t = .2 * (u_time + firstFrameOffset);\n vec3 totalColor = vec3(0.);\n float totalShape = 0.;\n float totalOpacity = 0.;\n vec2 weightedCenter = vec2(0.);\n vec2 weightedOrientation = vec2(0.);\n float centerWeight = 0.;\n\n for (int i = 0; i < 20; i++) {\n if (i >= int(ceil(u_count))) break;\n float idxFract = float(i) / 20.0;\n float angle = TWO_PI * idxFract;\n float speed = 1. - .2 * idxFract;\n vec2 pos = vec2(.5) + 1e-4 + .9 * (vec2(noise(angle * 10. + float(i) + t * speed), noise(angle * 20. + float(i) - t * speed)) - .5);\n int safeIndex = i % int(u_colorsCount + 0.5);\n vec4 ballColor = u_colors[safeIndex];\n ballColor.rgb *= ballColor.a;\n float sizeFrac = 1.;\n if (float(i) > floor(u_count - 1.)) sizeFrac *= fract(u_count);\n float shape = getBallShape(shape_uv, pos, 45. - 30. * u_size * sizeFrac);\n shape *= pow(u_size, .2);\n shape = smoothstep(0., 1., shape);\n totalColor += ballColor.rgb * shape;\n totalShape += shape;\n totalOpacity += ballColor.a * shape;\n float centerContribution = shape * shape;\n weightedCenter += pos * centerContribution;\n weightedOrientation += vec2(cos(angle), sin(angle)) * centerContribution;\n centerWeight += centerContribution;\n }\n\n totalColor /= max(totalShape, 1e-4);\n totalOpacity /= max(totalShape, 1e-4);\n float edgeWidth = fwidth(totalShape);\n float finalShape = smoothstep(.4, .4 + edgeWidth, totalShape);\n vec2 fieldCenter = weightedCenter / max(centerWeight, 1e-4);\n vec2 fieldVector = shape_uv - fieldCenter;\n float depth = smoothstep(0.4, 1.45, totalShape);\n float fieldRotation = 0.18 * atan(weightedOrientation.y, weightedOrientation.x);\n float rotationCos = cos(fieldRotation);\n float rotationSin = sin(fieldRotation);\n vec2 surfaceUV = fieldCenter + mat2(rotationCos, rotationSin, -rotationSin, rotationCos) * fieldVector * (1.0 + 0.1 * depth);\n vec2 gradient = vec2(dFdx(totalShape), dFdy(totalShape));\n vec2 gradientDirection = gradient / max(length(gradient), 1e-4);\n surfaceUV += gradientDirection * 0.008 * sin(totalShape * 4.0);\n float feature = surfacePattern(surfaceUV, depth, u_material, t);\n vec3 normal = normalize(vec3(-gradient * 36.0, 1.0));\n vec3 lightDirection = normalize(vec3(-0.45, 0.65, 0.8));\n float surfaceLight = 0.62 + 0.38 * max(dot(normal, lightDirection), 0.0);\n float baseSurface = mix(0.012, 0.06, depth);\n float surface = u_material < 0.5 ? 1.0 : mix(baseSurface, surfaceLight, feature);\n vec3 color = totalColor * finalShape * surface;\n float opacity = totalOpacity * finalShape * surface;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n color += 1. / 256. * (fract(sin(dot(.014 * gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453123) - .5);\n fragColor = vec4(color, opacity);\n}\n";
|
|
2
|
+
//# sourceMappingURL=shader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shader.d.ts","sourceRoot":"","sources":["../../../src/internal/agent-visual/shader.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,mBAAmB,+oMAuJ/B,CAAC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Modified from Paper Shaders 0.0.78 Metaballs (Apache-2.0).
|
|
3
|
+
* The metaball field, motion, colour blending, and edge calculation remain
|
|
4
|
+
* Paper's construction. `surfacePattern` clips the four approved NadicodeAI
|
|
5
|
+
* identity materials inside that generated form. Attribution ships in NOTICE.
|
|
6
|
+
*/
|
|
7
|
+
export const AGENT_VISUAL_SHADER = `#version 300 es
|
|
8
|
+
precision mediump float;
|
|
9
|
+
|
|
10
|
+
uniform float u_time;
|
|
11
|
+
uniform sampler2D u_noiseTexture;
|
|
12
|
+
uniform vec4 u_colorBack;
|
|
13
|
+
uniform vec4 u_colors[8];
|
|
14
|
+
uniform float u_colorsCount;
|
|
15
|
+
uniform float u_size;
|
|
16
|
+
uniform float u_count;
|
|
17
|
+
uniform float u_material;
|
|
18
|
+
uniform float u_detail;
|
|
19
|
+
uniform vec2 u_resolution;
|
|
20
|
+
|
|
21
|
+
in vec2 v_objectUV;
|
|
22
|
+
out vec4 fragColor;
|
|
23
|
+
|
|
24
|
+
#define TWO_PI 6.28318530718
|
|
25
|
+
|
|
26
|
+
float randomR(vec2 p) {
|
|
27
|
+
vec2 uv = floor(p) / 100. + .5;
|
|
28
|
+
return texture(u_noiseTexture, fract(uv)).r;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
float noise(float x) {
|
|
32
|
+
float i = floor(x);
|
|
33
|
+
float f = fract(x);
|
|
34
|
+
float u = f * f * (3.0 - 2.0 * f);
|
|
35
|
+
return mix(randomR(vec2(i, 0.0)), randomR(vec2(i + 1.0, 0.0)), u);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
float getBallShape(vec2 uv, vec2 c, float p) {
|
|
39
|
+
float s = .5 * length(uv - c);
|
|
40
|
+
s = 1. - clamp(s, 0., 1.);
|
|
41
|
+
return pow(s, p);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
float hash21(vec2 p) {
|
|
45
|
+
p = fract(p * vec2(123.34, 456.21));
|
|
46
|
+
p += dot(p, p + 45.32);
|
|
47
|
+
return fract(p.x * p.y);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
float orderedPoints(vec2 surfaceUV, float depth) {
|
|
51
|
+
float density = clamp(min(u_resolution.x, u_resolution.y) / 12.0 * u_detail, 6.0, 34.0);
|
|
52
|
+
vec2 pointUV = fract(surfaceUV * density) - 0.5;
|
|
53
|
+
float radius = mix(0.14, 0.23, depth);
|
|
54
|
+
return 1.0 - smoothstep(radius * 0.7, radius, length(pointUV));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
float triangularWire(vec2 surfaceUV, float depth) {
|
|
58
|
+
float density = clamp(min(u_resolution.x, u_resolution.y) / 16.0 * u_detail, 5.0, 26.0);
|
|
59
|
+
vec2 grid = surfaceUV * density;
|
|
60
|
+
float horizontal = abs(fract(grid.y) - 0.5);
|
|
61
|
+
float diagonalA = abs(fract(grid.x + grid.y * 0.5) - 0.5);
|
|
62
|
+
float diagonalB = abs(fract(grid.x - grid.y * 0.5) - 0.5);
|
|
63
|
+
float nearestLine = min(horizontal, min(diagonalA, diagonalB));
|
|
64
|
+
float width = mix(0.032, 0.072, depth);
|
|
65
|
+
return 1.0 - smoothstep(width * 0.55, width, nearestLine);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
float particleLayer(vec2 surfaceUV, float density, float depth, float time, float layerSeed, float threshold) {
|
|
69
|
+
vec2 gridUV = surfaceUV * density + layerSeed;
|
|
70
|
+
vec2 cell = floor(gridUV);
|
|
71
|
+
vec2 local = fract(gridUV) - 0.5;
|
|
72
|
+
float seed = hash21(cell + layerSeed);
|
|
73
|
+
vec2 jitter = vec2(hash21(cell + layerSeed + 3.17), hash21(cell + layerSeed + 8.41)) - 0.5;
|
|
74
|
+
jitter *= 0.72;
|
|
75
|
+
jitter += 0.08 * vec2(sin(time * 0.42 + seed * 18.0 + layerSeed), cos(time * 0.31 + seed * 14.0 - layerSeed));
|
|
76
|
+
float radius = mix(0.055, 0.175, hash21(cell + layerSeed + 14.3)) * mix(0.78, 1.35, depth);
|
|
77
|
+
float particle = 1.0 - smoothstep(radius * 0.68, radius, length(local - jitter));
|
|
78
|
+
float brightness = mix(0.45, 1.0, hash21(cell + layerSeed + 24.7));
|
|
79
|
+
return particle * step(threshold, seed) * brightness;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
float livingParticles(vec2 surfaceUV, float depth, float time) {
|
|
83
|
+
float density = clamp(min(u_resolution.x, u_resolution.y) / 6.5 * u_detail, 13.0, 68.0);
|
|
84
|
+
float dust = particleLayer(surfaceUV, density, depth, time, 0.0, 0.16);
|
|
85
|
+
float motes = particleLayer(surfaceUV, density * 0.46, depth, time * 0.72, 19.7, 0.62);
|
|
86
|
+
return max(dust * 0.78, motes);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
float surfacePattern(vec2 surfaceUV, float depth, float material, float time) {
|
|
90
|
+
if (material < 0.5) return 1.0;
|
|
91
|
+
if (material < 1.5) return orderedPoints(surfaceUV, depth);
|
|
92
|
+
if (material < 2.5) return triangularWire(surfaceUV, depth);
|
|
93
|
+
return livingParticles(surfaceUV, depth, time);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
void main() {
|
|
97
|
+
vec2 shape_uv = v_objectUV + .5;
|
|
98
|
+
const float firstFrameOffset = 2503.4;
|
|
99
|
+
float t = .2 * (u_time + firstFrameOffset);
|
|
100
|
+
vec3 totalColor = vec3(0.);
|
|
101
|
+
float totalShape = 0.;
|
|
102
|
+
float totalOpacity = 0.;
|
|
103
|
+
vec2 weightedCenter = vec2(0.);
|
|
104
|
+
vec2 weightedOrientation = vec2(0.);
|
|
105
|
+
float centerWeight = 0.;
|
|
106
|
+
|
|
107
|
+
for (int i = 0; i < 20; i++) {
|
|
108
|
+
if (i >= int(ceil(u_count))) break;
|
|
109
|
+
float idxFract = float(i) / 20.0;
|
|
110
|
+
float angle = TWO_PI * idxFract;
|
|
111
|
+
float speed = 1. - .2 * idxFract;
|
|
112
|
+
vec2 pos = vec2(.5) + 1e-4 + .9 * (vec2(noise(angle * 10. + float(i) + t * speed), noise(angle * 20. + float(i) - t * speed)) - .5);
|
|
113
|
+
int safeIndex = i % int(u_colorsCount + 0.5);
|
|
114
|
+
vec4 ballColor = u_colors[safeIndex];
|
|
115
|
+
ballColor.rgb *= ballColor.a;
|
|
116
|
+
float sizeFrac = 1.;
|
|
117
|
+
if (float(i) > floor(u_count - 1.)) sizeFrac *= fract(u_count);
|
|
118
|
+
float shape = getBallShape(shape_uv, pos, 45. - 30. * u_size * sizeFrac);
|
|
119
|
+
shape *= pow(u_size, .2);
|
|
120
|
+
shape = smoothstep(0., 1., shape);
|
|
121
|
+
totalColor += ballColor.rgb * shape;
|
|
122
|
+
totalShape += shape;
|
|
123
|
+
totalOpacity += ballColor.a * shape;
|
|
124
|
+
float centerContribution = shape * shape;
|
|
125
|
+
weightedCenter += pos * centerContribution;
|
|
126
|
+
weightedOrientation += vec2(cos(angle), sin(angle)) * centerContribution;
|
|
127
|
+
centerWeight += centerContribution;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
totalColor /= max(totalShape, 1e-4);
|
|
131
|
+
totalOpacity /= max(totalShape, 1e-4);
|
|
132
|
+
float edgeWidth = fwidth(totalShape);
|
|
133
|
+
float finalShape = smoothstep(.4, .4 + edgeWidth, totalShape);
|
|
134
|
+
vec2 fieldCenter = weightedCenter / max(centerWeight, 1e-4);
|
|
135
|
+
vec2 fieldVector = shape_uv - fieldCenter;
|
|
136
|
+
float depth = smoothstep(0.4, 1.45, totalShape);
|
|
137
|
+
float fieldRotation = 0.18 * atan(weightedOrientation.y, weightedOrientation.x);
|
|
138
|
+
float rotationCos = cos(fieldRotation);
|
|
139
|
+
float rotationSin = sin(fieldRotation);
|
|
140
|
+
vec2 surfaceUV = fieldCenter + mat2(rotationCos, rotationSin, -rotationSin, rotationCos) * fieldVector * (1.0 + 0.1 * depth);
|
|
141
|
+
vec2 gradient = vec2(dFdx(totalShape), dFdy(totalShape));
|
|
142
|
+
vec2 gradientDirection = gradient / max(length(gradient), 1e-4);
|
|
143
|
+
surfaceUV += gradientDirection * 0.008 * sin(totalShape * 4.0);
|
|
144
|
+
float feature = surfacePattern(surfaceUV, depth, u_material, t);
|
|
145
|
+
vec3 normal = normalize(vec3(-gradient * 36.0, 1.0));
|
|
146
|
+
vec3 lightDirection = normalize(vec3(-0.45, 0.65, 0.8));
|
|
147
|
+
float surfaceLight = 0.62 + 0.38 * max(dot(normal, lightDirection), 0.0);
|
|
148
|
+
float baseSurface = mix(0.012, 0.06, depth);
|
|
149
|
+
float surface = u_material < 0.5 ? 1.0 : mix(baseSurface, surfaceLight, feature);
|
|
150
|
+
vec3 color = totalColor * finalShape * surface;
|
|
151
|
+
float opacity = totalOpacity * finalShape * surface;
|
|
152
|
+
vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
|
|
153
|
+
color = color + bgColor * (1. - opacity);
|
|
154
|
+
opacity = opacity + u_colorBack.a * (1. - opacity);
|
|
155
|
+
color += 1. / 256. * (fract(sin(dot(.014 * gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453123) - .5);
|
|
156
|
+
fragColor = vec4(color, opacity);
|
|
157
|
+
}
|
|
158
|
+
`;
|
|
@@ -53,7 +53,7 @@ const ThreadSuggestionItem = () => {
|
|
|
53
53
|
return (_jsx("div", { className: "aui-thread-welcome-suggestion-display", children: _jsxs(SuggestionPrimitive.Trigger, { send: true, render: _jsx(Button, { variant: "ghost", className: "aui-thread-welcome-suggestion text-foreground hover:bg-muted border-border/60 h-auto gap-1.5 rounded-full border px-3.5 py-1.5 text-sm font-normal whitespace-nowrap transition-colors" }), children: [_jsx(SuggestionPrimitive.Title, { className: "aui-thread-welcome-suggestion-text-1" }), _jsx(SuggestionPrimitive.Description, { className: "aui-thread-welcome-suggestion-text-2 empty:hidden" })] }) }));
|
|
54
54
|
};
|
|
55
55
|
const Composer = () => {
|
|
56
|
-
return (_jsx(ComposerPrimitive.Root, { className: "aui-composer-root relative flex w-full flex-col", children: _jsxs(ComposerPrimitive.AttachmentDropzone, { render: _jsx("div", { "data-slot": "aui_composer-shell", className: "nc-transition-paint flex w-full flex-col gap-2 rounded-(--composer-radius) border border-border bg-(--composer-bg) p-(--composer-padding)
|
|
56
|
+
return (_jsx(ComposerPrimitive.Root, { className: "aui-composer-root relative flex w-full flex-col", children: _jsxs(ComposerPrimitive.AttachmentDropzone, { render: _jsx("div", { "data-slot": "aui_composer-shell", className: "nc-transition-paint flex w-full flex-col gap-2 rounded-(--composer-radius) border border-border bg-(--composer-bg) p-(--composer-padding) focus-within:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:border-ring data-[dragging=true]:bg-accent" }), children: [_jsx(ComposerAttachments, {}), _jsx(ComposerPrimitive.Input, { placeholder: "Send a message...", className: "aui-composer-input caret-primary placeholder:text-muted-foreground/80 max-h-32 min-h-10 w-full resize-none bg-transparent px-2.5 py-1 text-base outline-none", rows: 1, autoFocus: true, enterKeyHint: "send", "aria-label": "Message input" }), _jsx(ComposerAction, {})] }) }));
|
|
57
57
|
};
|
|
58
58
|
const ComposerAction = () => {
|
|
59
59
|
return (_jsxs("div", { className: "aui-composer-action-wrapper relative flex items-center justify-between", children: [_jsx(ComposerAddAttachment, {}), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs(AuiIf, { condition: (s) => s.thread.capabilities.dictation, children: [_jsx(AuiIf, { condition: (s) => s.composer.dictation == null, children: _jsx(ComposerPrimitive.Dictate, { render: _jsx(TooltipIconButton, { tooltip: "Voice input", side: "bottom", type: "button", variant: "ghost", size: "icon", className: "aui-composer-dictate size-7 rounded-full", "aria-label": "Start voice input" }), children: _jsx(MicIcon, { className: "aui-composer-dictate-icon size-4" }) }) }), _jsx(AuiIf, { condition: (s) => s.composer.dictation != null, children: _jsx(ComposerPrimitive.StopDictation, { render: _jsx(TooltipIconButton, { tooltip: "Stop dictation", side: "bottom", type: "button", variant: "ghost", size: "icon", className: "aui-composer-stop-dictation text-destructive size-7 rounded-full", "aria-label": "Stop voice input" }), children: _jsx(SquareIcon, { className: "aui-composer-stop-dictation-icon size-3.5 fill-current motion-safe:animate-pulse" }) }) })] }), _jsx(AuiIf, { condition: (s) => !s.thread.isRunning, children: _jsx(ComposerPrimitive.Send, { render: _jsx(TooltipIconButton, { tooltip: "Send message", side: "bottom", type: "button", variant: "default", size: "icon", className: "aui-composer-send size-7 rounded-full", "aria-label": "Send message" }), children: _jsx(ArrowUpIcon, { className: "aui-composer-send-icon size-4.5" }) }) }), _jsx(AuiIf, { condition: (s) => s.thread.isRunning, children: _jsx(ComposerPrimitive.Cancel, { render: _jsx(Button, { type: "button", variant: "default", size: "icon", className: "aui-composer-cancel size-7 rounded-full", "aria-label": "Stop generating" }), children: _jsx(SquareIcon, { className: "aui-composer-cancel-icon size-3.5 fill-current" }) }) })] })] }));
|
|
@@ -102,7 +102,7 @@ const AssistantMessage = () => {
|
|
|
102
102
|
} }), _jsx(MessageError, {})] }), _jsxs("div", { "data-slot": "aui_assistant-message-footer", className: cn("ms-2 flex items-center", ACTION_BAR_HEIGHT), children: [_jsx(BranchPicker, {}), _jsx(AssistantActionBar, {})] })] }));
|
|
103
103
|
};
|
|
104
104
|
const AssistantActionBar = () => {
|
|
105
|
-
return (_jsxs(ActionBarPrimitive.Root, { hideWhenRunning: true, autohide: "not-last", className: "aui-assistant-action-bar-root nc-transition-opacity col-start-3 row-start-2 -ms-1 flex gap-1 text-muted-foreground", children: [_jsxs(ActionBarPrimitive.Copy, { render: _jsx(TooltipIconButton, { tooltip: "Copy" }), children: [_jsx(AuiIf, { condition: (s) => s.message.isCopied, children: _jsx(CheckIcon, {}) }), _jsx(AuiIf, { condition: (s) => !s.message.isCopied, children: _jsx(CopyIcon, {}) })] }), _jsx(ActionBarPrimitive.Reload, { render: _jsx(TooltipIconButton, { tooltip: "Refresh" }), children: _jsx(RefreshCwIcon, {}) }), _jsxs(ActionBarMorePrimitive.Root, { children: [_jsx(ActionBarMorePrimitive.Trigger, { render: _jsx(TooltipIconButton, { tooltip: "More", className: "data-[state=open]:bg-accent" }), children: _jsx(MoreHorizontalIcon, {}) }), _jsx(ActionBarMorePrimitive.Content, { side: "bottom", align: "start", sideOffset: 6, className: "aui-action-bar-more-content nc-transition-opacity bg-popover
|
|
105
|
+
return (_jsxs(ActionBarPrimitive.Root, { hideWhenRunning: true, autohide: "not-last", className: "aui-assistant-action-bar-root nc-transition-opacity col-start-3 row-start-2 -ms-1 flex gap-1 text-muted-foreground", children: [_jsxs(ActionBarPrimitive.Copy, { render: _jsx(TooltipIconButton, { tooltip: "Copy" }), children: [_jsx(AuiIf, { condition: (s) => s.message.isCopied, children: _jsx(CheckIcon, {}) }), _jsx(AuiIf, { condition: (s) => !s.message.isCopied, children: _jsx(CopyIcon, {}) })] }), _jsx(ActionBarPrimitive.Reload, { render: _jsx(TooltipIconButton, { tooltip: "Refresh" }), children: _jsx(RefreshCwIcon, {}) }), _jsxs(ActionBarMorePrimitive.Root, { children: [_jsx(ActionBarMorePrimitive.Trigger, { render: _jsx(TooltipIconButton, { tooltip: "More", className: "data-[state=open]:bg-accent" }), children: _jsx(MoreHorizontalIcon, {}) }), _jsx(ActionBarMorePrimitive.Content, { side: "bottom", align: "start", sideOffset: 6, className: "aui-action-bar-more-content nc-transition-opacity z-50 min-w-[8rem] overflow-hidden rounded-xl border-0 bg-popover p-1.5 text-popover-foreground smooth-shadow-ring-xl data-[state=closed]:opacity-0 data-[state=open]:opacity-100", children: _jsxs(ActionBarPrimitive.ExportMarkdown, { render: _jsx(ActionBarMorePrimitive.Item, { className: "aui-action-bar-more-item hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground flex cursor-pointer items-center gap-2 rounded-lg px-2.5 py-1.5 text-sm outline-none select-none" }), children: [_jsx(DownloadIcon, { className: "size-4" }), "Export as Markdown"] }) })] })] }));
|
|
106
106
|
};
|
|
107
107
|
const UserMessage = () => {
|
|
108
108
|
return (_jsxs(MessagePrimitive.Root, { "data-slot": "aui_user-message-root", className: "grid auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 [contain-intrinsic-size:auto_200px] [content-visibility:auto] [&:where(>*)]:col-start-2", "data-role": "user", children: [_jsx(UserMessageAttachments, {}), _jsxs("div", { className: "aui-user-message-content-wrapper relative col-start-2 min-w-0", children: [_jsx("div", { className: "aui-user-message-content peer bg-muted text-foreground rounded-xl px-4 py-2 wrap-break-word empty:hidden", children: _jsx(MessagePrimitive.Parts, {}) }), _jsx("div", { className: "aui-user-action-bar-wrapper absolute start-0 top-1/2 -translate-x-full -translate-y-1/2 pe-2 peer-empty:hidden rtl:translate-x-full", children: _jsx(UserActionBar, {}) })] }), _jsx(BranchPicker, { "data-slot": "aui_user-branch-picker", className: "col-span-full col-start-1 row-start-3 -me-1 justify-end" })] }));
|
|
@@ -111,7 +111,7 @@ const UserActionBar = () => {
|
|
|
111
111
|
return (_jsx(ActionBarPrimitive.Root, { hideWhenRunning: true, autohide: "not-last", className: "aui-user-action-bar-root flex flex-col items-end", children: _jsx(ActionBarPrimitive.Edit, { render: _jsx(TooltipIconButton, { tooltip: "Edit", className: "aui-user-action-edit" }), children: _jsx(PencilIcon, {}) }) }));
|
|
112
112
|
};
|
|
113
113
|
const EditComposer = () => {
|
|
114
|
-
return (_jsx(MessagePrimitive.Root, { "data-slot": "aui_edit-composer-wrapper", className: "flex flex-col px-2 [contain-intrinsic-size:auto_200px] [content-visibility:auto]", children: _jsxs(ComposerPrimitive.Root, { className: "aui-edit-composer-root ms-auto flex w-full max-w-[85%] flex-col rounded-(--composer-radius) border border-border bg-(--composer-bg)
|
|
114
|
+
return (_jsx(MessagePrimitive.Root, { "data-slot": "aui_edit-composer-wrapper", className: "flex flex-col px-2 [contain-intrinsic-size:auto_200px] [content-visibility:auto]", children: _jsxs(ComposerPrimitive.Root, { className: "aui-edit-composer-root ms-auto flex w-full max-w-[85%] flex-col rounded-(--composer-radius) border border-border bg-(--composer-bg)", children: [_jsx(ComposerPrimitive.Input, { className: "aui-edit-composer-input text-foreground min-h-14 w-full resize-none bg-transparent px-4 pt-3 pb-1 text-base outline-none", autoFocus: true }), _jsxs("div", { className: "aui-edit-composer-footer mx-2.5 mb-2.5 flex items-center gap-1.5 self-end", children: [_jsx(ComposerPrimitive.Cancel, { render: _jsx(Button, { variant: "ghost", size: "sm", className: "h-8 rounded-full px-3.5" }), children: "Cancel" }), _jsx(ComposerPrimitive.Send, { render: _jsx(Button, { size: "sm", className: "h-8 rounded-full px-3.5" }), children: "Update" })] })] }) }));
|
|
115
115
|
};
|
|
116
116
|
const BranchPicker = ({ className, ...rest }) => {
|
|
117
117
|
return (_jsxs(BranchPickerPrimitive.Root, { hideWhenSingleBranch: true, className: cn("aui-branch-picker-root text-muted-foreground -ms-2 me-2 inline-flex items-center text-xs", className), ...rest, children: [_jsx(BranchPickerPrimitive.Previous, { render: _jsx(TooltipIconButton, { tooltip: "Previous" }), children: _jsx(ChevronLeftIcon, {}) }), _jsxs("span", { className: "aui-branch-picker-state font-medium", children: [_jsx(BranchPickerPrimitive.Number, {}), " / ", _jsx(BranchPickerPrimitive.Count, {})] }), _jsx(BranchPickerPrimitive.Next, { render: _jsx(TooltipIconButton, { tooltip: "Next" }), children: _jsx(ChevronRightIcon, {}) })] }));
|
package/dist/styles/globals.css
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
@layer tokens, theme, reset, base, foundation, motion, layout, primitives, components, utilities;
|
|
15
15
|
|
|
16
16
|
@import "tailwindcss";
|
|
17
|
+
@import "shadow-plugin";
|
|
17
18
|
@import "tw-animate-css";
|
|
18
19
|
@import "tw-shimmer";
|
|
19
20
|
@import "@assistant-ui/react-markdown/styles/dot.css";
|
|
@@ -53,6 +54,25 @@
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
@layer components {
|
|
58
|
+
.nc-glass-control {
|
|
59
|
+
background: color-mix(in srgb, var(--popover) var(--nc-material-glass-opacity), transparent);
|
|
60
|
+
backdrop-filter: blur(var(--nc-material-glass-blur))
|
|
61
|
+
saturate(var(--nc-material-glass-saturation));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.nc-toast {
|
|
65
|
+
border: 0 !important;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
69
|
+
.nc-glass-control {
|
|
70
|
+
background: var(--popover);
|
|
71
|
+
backdrop-filter: none;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
56
76
|
/*
|
|
57
77
|
* The canonical design-system module owns raw --nc-* mode aliases, semantic
|
|
58
78
|
* roles, and their Tailwind utility bridge for both root and scoped `.dark`
|
|
@@ -86,4 +106,5 @@
|
|
|
86
106
|
}
|
|
87
107
|
|
|
88
108
|
@source "../components";
|
|
109
|
+
@source "../internal";
|
|
89
110
|
@source "../lib";
|
|
@@ -36,5 +36,7 @@ Use shadcn MCP or the CLI live; never commit an upstream registry inventory.
|
|
|
36
36
|
the committed package surface. Preview upstream changes before applying them;
|
|
37
37
|
do not overwrite maintained source without explicit maintainer direction.
|
|
38
38
|
|
|
39
|
-
The package [`AGENTS.md`](../../AGENTS.md) maps scoped commands.
|
|
40
|
-
|
|
39
|
+
The package [`AGENTS.md`](../../AGENTS.md) maps scoped commands. Proof escalates
|
|
40
|
+
by the ladder in the repository's root `AGENTS.md` "Commands": this workspace's
|
|
41
|
+
`check` and `test`, then the root `npm run check` and `npm run test` when the
|
|
42
|
+
diff reaches other workspaces.
|
|
@@ -42,7 +42,9 @@ import "@nadicodeai/ui/globals.css";
|
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
`@nadicodeai/ui/globals.css` is the complete React style interface. It composes
|
|
45
|
-
Tailwind v4, shadcn,
|
|
45
|
+
Tailwind v4, shadcn, the exact smooth-shadow plugin, and the complete
|
|
46
|
+
design-system CSS module. Consumers do not import `shadow-plugin`, restyle its
|
|
47
|
+
optical ring, or add a second border/ring to package-owned elevated roots.
|
|
46
48
|
Do not import `@nadicodeai/design-system/css`, generated theme files, or CSS
|
|
47
49
|
partials beside it. The package declares its own built component sources; Tailwind's
|
|
48
50
|
normal automatic detection covers the consumer application. The app still owns
|
package/docs/contract.md
CHANGED
|
@@ -9,18 +9,96 @@ The normative invariants for the `@nadicodeai/ui` package: what may live here, h
|
|
|
9
9
|
- **Components inherit one complete React style interface.** `@nadicodeai/ui/globals.css` composes every style dependency owned by this package, including the complete design-system CSS module. Components carry no theme of their own, and React callers do not compose design-system stylesheets or partials beside it. Installation and source-scanning setup live in the [consumer setup guide](consuming-cross-repo.md).
|
|
10
10
|
- **Design-system geometry remains the foundation.** React components compose the kept `nc-*` page grammar and display CSS components; they do not redefine frame math, marker placement, token values, or raw CSS geometry. Use parent-paints-plus-gap for bordered cell grids and keep every visible seam single-owner (doctrine home: `design-system/DESIGN.md` "## Layout").
|
|
11
11
|
|
|
12
|
+
### Material surfaces
|
|
13
|
+
|
|
14
|
+
`shadow-plugin@1.2.7` enters once through `@nadicodeai/ui/globals.css`. Its
|
|
15
|
+
integrated optical ring is part of every elevated shadow and remains at the
|
|
16
|
+
vendor default, including the 18% white dark-mode ring. Never pair a
|
|
17
|
+
`smooth-shadow-ring-*` root with `border-*`, a separate `ring-*`,
|
|
18
|
+
`smooth-ring-*`, or a local `--smooth-ring-color` override.
|
|
19
|
+
|
|
20
|
+
Physical role, not content importance, chooses depth:
|
|
21
|
+
|
|
22
|
+
- `Card surface="resting"` (the default) uses `smooth-shadow-ring-md`.
|
|
23
|
+
- `Card surface="raised"` uses `smooth-shadow-ring-lg`; active or selected
|
|
24
|
+
work chooses it explicitly.
|
|
25
|
+
- `Card surface="plain"` is the explicit structural/auth/website escape and
|
|
26
|
+
carries no elevation.
|
|
27
|
+
- Tooltip, menu, popover, select, combobox, navigation popup, hover card,
|
|
28
|
+
chart tooltip, and toast roots own `smooth-shadow-ring-xl` internally.
|
|
29
|
+
- Dialog, alert dialog, drawer, and sheet roots own
|
|
30
|
+
`smooth-shadow-ring-2xl` internally.
|
|
31
|
+
|
|
32
|
+
All solid surfaces use the one semantic fill. Dark mode therefore stays true
|
|
33
|
+
black; depth never comes from progressively greyer cards. Because the plugin
|
|
34
|
+
owns `box-shadow` with `!important`, focus on an elevated root uses the
|
|
35
|
+
canonical outline rather than another box-shadow ring.
|
|
36
|
+
|
|
37
|
+
`GlassControl` is the only shared glass material. It is control chrome,
|
|
38
|
+
using `shape="control"` for compact floating controls and `shape="bar"` for
|
|
39
|
+
full-width header chrome. Cards and modal primitives continue to own page
|
|
40
|
+
content, KPIs, tables, inspectors, and dialog bodies. Reduced transparency
|
|
41
|
+
falls back to the same solid floating surface.
|
|
42
|
+
|
|
43
|
+
`Empty` makes containment explicit with `scope="page" | "region" | "card"`.
|
|
44
|
+
Page and region states own one opaque dashed boundary. A Card-scoped Empty is
|
|
45
|
+
transparent and unframed because the Card already owns containment.
|
|
46
|
+
|
|
47
|
+
## Status Vocabulary
|
|
48
|
+
|
|
49
|
+
`Badge` is the product's only status carrier. It ships five semantic tone
|
|
50
|
+
variants — `gray`, `green`, `red`, `amber`, `blue` — each one soft/deep pair
|
|
51
|
+
from the generated tokens (`--nc-canvas-soft-2`/`--nc-body`,
|
|
52
|
+
`--nc-link-bg-soft`/`--nc-link-deep`, `--nc-error-soft`/`--nc-error-deep`,
|
|
53
|
+
`--nc-warning-soft`/`--nc-warning-deep`, `--nc-info-soft`/`--nc-info-deep`), so
|
|
54
|
+
a status clears AA in both modes without a call site painting anything. A status
|
|
55
|
+
badge carries a mark in the existing icon slot beside its word, because colour
|
|
56
|
+
must never be the only thing that says what the status is; the mark is
|
|
57
|
+
`aria-hidden`, and the word is the accessible status. The tones are variants,
|
|
58
|
+
not utilities, precisely so `nadicodeai/no-shadcn-appearance-override` and
|
|
59
|
+
`nadicodeai/no-raw-color-utility` can keep them here.
|
|
60
|
+
|
|
61
|
+
What this package does not own: which statuses exist, which tone and which mark
|
|
62
|
+
each value takes, and the words. Those are the consuming app's domain — the
|
|
63
|
+
Portal maps them in one kit module and nothing else picks a status colour. The
|
|
64
|
+
design-system side of the decision, and why the retired CSS status grammars are
|
|
65
|
+
gone, is [`design-system/DESIGN.md`, "## Status Vocabulary"](../../../design-system/DESIGN.md#status-vocabulary).
|
|
66
|
+
|
|
12
67
|
## Package Shape Invariants
|
|
13
68
|
|
|
14
69
|
- **Source-authored, built package.** Components are authored as shadcn-style source in `src/`, then emitted to `dist/` for consumption by other apps. Package exports must point at built JS, declarations, and CSS, never raw `src/*.tsx`, and `npm pack --dry-run` must include only intentional consumer artifacts.
|
|
15
70
|
- **Package surface is source-backed.** Public components stay flat under `src/components/`. Reviewed registry source under `src/internal/` is implementation, not a package namespace. Do not add top-level exports for recipes, blocks, agent, terminal, or vendor groupings unless a later package API decision adds concrete public source, built files, docs, and tests in the same change.
|
|
16
|
-
- **Agents is the
|
|
71
|
+
- **Agents is the client-only conversation interface.** `@nadicodeai/ui/agents` re-exports the complete `@assistant-ui/react` runtime and primitive API plus the reviewed, branded registry composition held under `src/internal/assistant-ui/`. Its built entry retains `"use client"`. Consumers receive Thread, attachments, Markdown, reasoning, tools, suggestions, providers, runtimes, hooks, and types from that one domain namespace. Agent identity components use their direct component subpaths so server compositions do not import the conversation runtime. The vendor name is not a public NadicodeAI subpath, and the package does not rename, wrap, or rebuild assistant-ui behavior.
|
|
17
72
|
- **Base UI is the active primitive base.** `components.json` must resolve through a Base style, currently `base-nova`, and `npx shadcn@latest info --json` must report `base: "base"`. Do not reintroduce `radix-ui`, `@radix-ui/*`, or `vaul` to package source, dependencies, or app optimizer configuration. Registry-owned shadcn primitives stay aligned with current `shadcn@latest` Base UI output; use Base UI `render` composition instead of Radix `asChild`. `cmdk` is allowed only for the stock shadcn Command component while the current `base-nova` registry declares that dependency; do not use it elsewhere or replace it without a shadcn/compatibility decision and tests.
|
|
18
73
|
- **Named shadcn blocks stay named.** When a user, plan, or issue selects a shadcn block/example such as `login-02`, `signup-02`, `dashboard-01`, or `sidebar-*`, use that registry item as the source of truth through shadcn CLI/MCP. Do not replace it with a package-authored abstraction unless the plan explicitly records the substitution, the reason, and the true consumer route that proves it.
|
|
19
74
|
- **Public surface changes require a release decision.** Any change to exported components, `src/index.ts`, package `exports`, `globals.css`, theme behavior, package docs, package skills, or design-system token/CSS/theme output consumed by this package must end with an explicit npm release decision before handoff: bump the relevant version(s) and run `npm pack --dry-run -w @nadicodeai/ui` per `../../../docs/internal/npm-publishing.md`, or include a `[no-publish]` commit marker with the reason in the commit body. The pre-push gate requires one of the two. When the UI change depends on modified `@nadicodeai/design-system` output, bump and publish `@nadicodeai/design-system` first, then update this package's dependency and publish UI. Never claim a UI package change is shipped until `npm view @nadicodeai/ui version` reports the intended version.
|
|
20
75
|
|
|
21
76
|
## Admission Rules
|
|
22
77
|
|
|
23
|
-
|
|
78
|
+
Assistant conversation and runtime APIs enter through `@nadicodeai/ui/agents`; Agent identity enters through `@nadicodeai/ui/components/agent-card` and `@nadicodeai/ui/components/agent-visual`. The consuming application still constructs the runtime and owns transport, persistence, permissions, tools, approvals, and failure policy. Shared non-Agent product components (a shell, a settings surface, a generic section, a diff, or a file preview) are admitted only with a named consuming surface landing in the same change. App-bespoke UI and behavior (window chrome, boot/install overlays, mascots, PTY/xterm embeds, queues, approvals, and persistence) stay in the consuming app; they never become package abstractions. A component left unconsumed after its target migration ships gets removed.
|
|
79
|
+
|
|
80
|
+
### Agent identity presentation
|
|
81
|
+
|
|
82
|
+
`AgentVisual` is the shared branded identity renderer. Its public degrees of
|
|
83
|
+
freedom are deliberately closed: one of `general`, `reasoning`,
|
|
84
|
+
`coordination`, `communication`, or `execution`, plus the structural
|
|
85
|
+
presentation `registry`, `card`, or `detail`. Consumers cannot supply colours,
|
|
86
|
+
shader code, speed, count, density, frame, or material. Every presentation
|
|
87
|
+
mounts the same ambient Paper Metaballs renderer after the reduced-motion
|
|
88
|
+
check. The shared component mounts it only while the visual intersects the
|
|
89
|
+
viewport, releasing its WebGL context offscreen; the vendor pauses it when the
|
|
90
|
+
document is hidden. SSR, first paint, reduced motion,
|
|
91
|
+
missing WebGL, initialization failure, and context loss retain the same
|
|
92
|
+
deterministic poster. The visual is decorative by default. A meaningful
|
|
93
|
+
selectable image opts into `decorative={false}` and supplies `label`.
|
|
94
|
+
|
|
95
|
+
`AgentCard` composes the fundamental `Card` with explicit `visual`, `name`,
|
|
96
|
+
`job`, `status`, `meta`, and `action` slots. It owns presentation only. The app
|
|
97
|
+
still owns Agent data, recipe assignment, status grammar, routing, actions, and
|
|
98
|
+
heading hierarchy; when the Card is the page identity, the `name` slot carries
|
|
99
|
+
that page's `h1`.
|
|
100
|
+
There is no `AgentGlyph`, `AgentRow`, `KpiCard`, or product-domain `agent`
|
|
101
|
+
object prop in the shared package.
|
|
24
102
|
|
|
25
103
|
- **Standard components, not app-owned product features.** This package ships primitives, standard UI components, assistant-ui compositions, brand adapters, React adapters, reusable sections, and presentational product components. It must not ship app-specific feature/use-case screens or names such as operator-login, portal activation, customer credential control, or customer management. Generic data tables, command palettes, and chart cards are app-owned shadcn registry adaptations. The source-backed `chart-*` package surface is the plan-approved exception per issue #166 and ADR 0010; chart cards remain app-owned. Every data-shaped chart exposes an equivalent non-visual data alternative. A component whose complete value is already available in visible text or `aria-valuetext` does not add a redundant table.
|
|
26
104
|
- **Auth routes are consumer-owned shadcn block work.** Login, signup, OTP, two-factor, magic-link, and provider-button flows start from the selected shadcn block/example in the consuming app, with app-owned Better Auth behavior. Do not ship generic auth, signup, OTP, federated-login, or provider abstractions from this package unless a later explicit boundary decision replaces the selected shadcn block.
|