create-stylus-ide 1.0.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 (135) hide show
  1. package/Readme.MD +1515 -0
  2. package/cli.js +28 -0
  3. package/frontend/.vscode/settings.json +9 -0
  4. package/frontend/app/api/chat/route.ts +101 -0
  5. package/frontend/app/api/check-setup/route.ts +93 -0
  6. package/frontend/app/api/cleanup/route.ts +14 -0
  7. package/frontend/app/api/compile/route.ts +95 -0
  8. package/frontend/app/api/compile-stream/route.ts +98 -0
  9. package/frontend/app/api/complete/route.ts +86 -0
  10. package/frontend/app/api/deploy/route.ts +118 -0
  11. package/frontend/app/api/export-abi/route.ts +58 -0
  12. package/frontend/app/favicon.ico +0 -0
  13. package/frontend/app/globals.css +177 -0
  14. package/frontend/app/layout.tsx +29 -0
  15. package/frontend/app/ml/page.tsx +694 -0
  16. package/frontend/app/page.tsx +1132 -0
  17. package/frontend/app/providers.tsx +18 -0
  18. package/frontend/app/qlearning/page.tsx +188 -0
  19. package/frontend/app/raytracing/page.tsx +268 -0
  20. package/frontend/components/abi/ABIDialog.tsx +132 -0
  21. package/frontend/components/ai/AICompletionPopup.tsx +76 -0
  22. package/frontend/components/ai/ChatPanel.tsx +292 -0
  23. package/frontend/components/ai/QuickActions.tsx +128 -0
  24. package/frontend/components/blockchain/BlockchainContractBanner.tsx +64 -0
  25. package/frontend/components/blockchain/BlockchainLoadingDialog.tsx +188 -0
  26. package/frontend/components/deploy/DeployDialog.tsx +334 -0
  27. package/frontend/components/editor/FileTabs.tsx +181 -0
  28. package/frontend/components/editor/MonacoEditor.tsx +306 -0
  29. package/frontend/components/file-tree/ContextMenu.tsx +110 -0
  30. package/frontend/components/file-tree/DeleteConfirmDialog.tsx +61 -0
  31. package/frontend/components/file-tree/FileInputDialog.tsx +97 -0
  32. package/frontend/components/file-tree/FileNode.tsx +60 -0
  33. package/frontend/components/file-tree/FileTree.tsx +259 -0
  34. package/frontend/components/file-tree/FileTreeSkeleton.tsx +26 -0
  35. package/frontend/components/file-tree/FolderNode.tsx +105 -0
  36. package/frontend/components/github/GitHubLoadingDialog.tsx +201 -0
  37. package/frontend/components/github/GitHubMetadataBanner.tsx +61 -0
  38. package/frontend/components/github/LoadFromGitHubDialog.tsx +125 -0
  39. package/frontend/components/github/URLCopyButton.tsx +60 -0
  40. package/frontend/components/interact/ContractInteraction.tsx +323 -0
  41. package/frontend/components/interact/ContractPlaceholder.tsx +41 -0
  42. package/frontend/components/orbit/BenchmarkDialog.tsx +342 -0
  43. package/frontend/components/orbit/OrbitExplorer.tsx +273 -0
  44. package/frontend/components/project/ProjectActions.tsx +176 -0
  45. package/frontend/components/q-learning/ContractConfig.tsx +172 -0
  46. package/frontend/components/q-learning/MazeGrid.tsx +346 -0
  47. package/frontend/components/q-learning/PathAnimation.tsx +384 -0
  48. package/frontend/components/q-learning/QTableHeatmap.tsx +300 -0
  49. package/frontend/components/q-learning/TrainingForm.tsx +349 -0
  50. package/frontend/components/ray-tracing/ContractConfig.tsx +245 -0
  51. package/frontend/components/ray-tracing/MintingForm.tsx +280 -0
  52. package/frontend/components/ray-tracing/RenderCanvas.tsx +228 -0
  53. package/frontend/components/ray-tracing/RenderingPanel.tsx +259 -0
  54. package/frontend/components/ray-tracing/StyleControls.tsx +217 -0
  55. package/frontend/components/setup/SetupGuide.tsx +290 -0
  56. package/frontend/components/ui/KeyboardShortcutHint.tsx +74 -0
  57. package/frontend/components/ui/alert-dialog.tsx +157 -0
  58. package/frontend/components/ui/alert.tsx +66 -0
  59. package/frontend/components/ui/badge.tsx +46 -0
  60. package/frontend/components/ui/button.tsx +62 -0
  61. package/frontend/components/ui/card.tsx +92 -0
  62. package/frontend/components/ui/context-menu.tsx +252 -0
  63. package/frontend/components/ui/dialog.tsx +143 -0
  64. package/frontend/components/ui/dropdown-menu.tsx +257 -0
  65. package/frontend/components/ui/input.tsx +21 -0
  66. package/frontend/components/ui/label.tsx +24 -0
  67. package/frontend/components/ui/progress.tsx +31 -0
  68. package/frontend/components/ui/scroll-area.tsx +58 -0
  69. package/frontend/components/ui/select.tsx +190 -0
  70. package/frontend/components/ui/separator.tsx +28 -0
  71. package/frontend/components/ui/sheet.tsx +139 -0
  72. package/frontend/components/ui/skeleton.tsx +13 -0
  73. package/frontend/components/ui/slider.tsx +63 -0
  74. package/frontend/components/ui/sonner.tsx +40 -0
  75. package/frontend/components/ui/tabs.tsx +66 -0
  76. package/frontend/components/ui/textarea.tsx +18 -0
  77. package/frontend/components/wallet/ConnectButton.tsx +167 -0
  78. package/frontend/components/wallet/FaucetButton.tsx +256 -0
  79. package/frontend/components.json +22 -0
  80. package/frontend/eslint.config.mjs +18 -0
  81. package/frontend/hooks/useAICompletion.ts +75 -0
  82. package/frontend/hooks/useBlockchainLoader.ts +58 -0
  83. package/frontend/hooks/useChats.ts +137 -0
  84. package/frontend/hooks/useCompilation.ts +173 -0
  85. package/frontend/hooks/useFileTabs.ts +178 -0
  86. package/frontend/hooks/useGitHubLoader.ts +50 -0
  87. package/frontend/hooks/useKeyboardShortcuts.ts +47 -0
  88. package/frontend/hooks/usePanelState.ts +115 -0
  89. package/frontend/hooks/useProjectState.ts +276 -0
  90. package/frontend/hooks/useResponsive.ts +29 -0
  91. package/frontend/lib/abi-parser.ts +58 -0
  92. package/frontend/lib/blockchain-api.ts +374 -0
  93. package/frontend/lib/blockchain-explorers.ts +75 -0
  94. package/frontend/lib/blockchain-loader.ts +112 -0
  95. package/frontend/lib/cargo-template.ts +64 -0
  96. package/frontend/lib/compilation.ts +529 -0
  97. package/frontend/lib/constants.ts +31 -0
  98. package/frontend/lib/deployment.ts +176 -0
  99. package/frontend/lib/file-utils.ts +83 -0
  100. package/frontend/lib/github-api.ts +246 -0
  101. package/frontend/lib/github-loader.ts +369 -0
  102. package/frontend/lib/ml-contract-template.txt +900 -0
  103. package/frontend/lib/orbit-chains.ts +181 -0
  104. package/frontend/lib/output-formatter.ts +68 -0
  105. package/frontend/lib/project-manager.ts +632 -0
  106. package/frontend/lib/ray-tracing-abi.ts +206 -0
  107. package/frontend/lib/storage.ts +189 -0
  108. package/frontend/lib/templates.ts +1662 -0
  109. package/frontend/lib/url-parser.ts +188 -0
  110. package/frontend/lib/utils.ts +6 -0
  111. package/frontend/lib/wagmi-config.ts +24 -0
  112. package/frontend/next.config.ts +7 -0
  113. package/frontend/package-lock.json +16259 -0
  114. package/frontend/package.json +60 -0
  115. package/frontend/postcss.config.mjs +7 -0
  116. package/frontend/public/file.svg +1 -0
  117. package/frontend/public/globe.svg +1 -0
  118. package/frontend/public/ml-weights/.gitkeep +0 -0
  119. package/frontend/public/ml-weights/model.pkl +0 -0
  120. package/frontend/public/ml-weights/model_weights.json +27102 -0
  121. package/frontend/public/ml-weights/test_samples.json +7888 -0
  122. package/frontend/public/next.svg +1 -0
  123. package/frontend/public/vercel.svg +1 -0
  124. package/frontend/public/window.svg +1 -0
  125. package/frontend/scripts/check-env.js +52 -0
  126. package/frontend/scripts/setup.js +285 -0
  127. package/frontend/tailwind.config.ts +64 -0
  128. package/frontend/tsconfig.json +34 -0
  129. package/frontend/types/blockchain.ts +63 -0
  130. package/frontend/types/github.ts +54 -0
  131. package/frontend/types/project.ts +106 -0
  132. package/ml-training/README.md +56 -0
  133. package/ml-training/train_tiny_model.py +325 -0
  134. package/ml-training/update_template.py +59 -0
  135. package/package.json +30 -0
@@ -0,0 +1,259 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { Button } from '@/components/ui/button';
5
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
6
+ import { Input } from '@/components/ui/input';
7
+ import { Label } from '@/components/ui/label';
8
+ import { Loader2, Image as ImageIcon, Download, ExternalLink } from 'lucide-react';
9
+ import { usePublicClient } from 'wagmi';
10
+ import { arbitrumSepolia } from 'wagmi/chains';
11
+ import { RAY_TRACING_ABI } from '@/lib/ray-tracing-abi';
12
+ import { bytesToImageData } from '@/lib/ray-tracing-abi';
13
+ import { useEffect, useRef } from 'react';
14
+
15
+ interface RenderingPanelProps {
16
+ nftAddress: string;
17
+ isNftConnected: boolean;
18
+ mintedTokenId: bigint | null;
19
+ }
20
+
21
+ export function RenderingPanel({
22
+ nftAddress,
23
+ isNftConnected,
24
+ mintedTokenId,
25
+ }: RenderingPanelProps) {
26
+ const [tokenIdInput, setTokenIdInput] = useState('');
27
+ const [isRendering, setIsRendering] = useState(false);
28
+ const [renderedData, setRenderedData] = useState<Uint8Array | null>(null);
29
+ const [renderError, setRenderError] = useState<string | null>(null);
30
+ const [gasUsed, setGasUsed] = useState<string | null>(null);
31
+
32
+ const canvasRef = useRef<HTMLCanvasElement>(null);
33
+ const publicClient = usePublicClient({ chainId: arbitrumSepolia.id });
34
+
35
+ // Auto-fill with minted token ID
36
+ useEffect(() => {
37
+ if (mintedTokenId !== null) {
38
+ setTokenIdInput(mintedTokenId.toString());
39
+ }
40
+ }, [mintedTokenId]);
41
+
42
+ const handleRender = async () => {
43
+ if (!publicClient || !tokenIdInput) {
44
+ alert('Please enter a token ID');
45
+ return;
46
+ }
47
+
48
+ setIsRendering(true);
49
+ setRenderError(null);
50
+ setGasUsed('120000'); // Estimated gas
51
+
52
+ try {
53
+ const tokenId = BigInt(tokenIdInput);
54
+
55
+ // Call the render function
56
+ const result = await publicClient.readContract({
57
+ address: nftAddress as `0x${string}`,
58
+ abi: RAY_TRACING_ABI as any,
59
+ functionName: 'renderToken', // Changed from render_token
60
+ args: [tokenId],
61
+ });
62
+
63
+ // Convert hex string to Uint8Array
64
+ const hexString = (result as string).slice(2); // Remove '0x' prefix
65
+ const bytes = new Uint8Array(hexString.length / 2);
66
+ for (let i = 0; i < bytes.length; i++) {
67
+ bytes[i] = parseInt(hexString.substring(i * 2, i * 2 + 2), 16);
68
+ }
69
+
70
+ if (bytes.length !== 3072) {
71
+ throw new Error(`Expected 3,072 bytes, got ${bytes.length}`);
72
+ }
73
+
74
+ setRenderedData(bytes);
75
+ renderToCanvas(bytes);
76
+ } catch (error: any) {
77
+ console.error('Rendering failed:', error);
78
+ setRenderError(error.message || 'Failed to render. Check token ID and contract.');
79
+ } finally {
80
+ setIsRendering(false);
81
+ }
82
+ };
83
+
84
+ const renderToCanvas = (pixelData: Uint8Array) => {
85
+ if (!canvasRef.current) return;
86
+
87
+ const canvas = canvasRef.current;
88
+ const ctx = canvas.getContext('2d');
89
+ if (!ctx) return;
90
+
91
+ const width = 32;
92
+ const height = 32;
93
+ canvas.width = width;
94
+ canvas.height = height;
95
+
96
+ // Create ImageData from pixel bytes
97
+ const imageData = ctx.createImageData(width, height);
98
+
99
+ for (let i = 0; i < pixelData.length; i += 3) {
100
+ const pixelIndex = i / 3;
101
+ const dataIndex = pixelIndex * 4;
102
+
103
+ imageData.data[dataIndex] = pixelData[i]; // R
104
+ imageData.data[dataIndex + 1] = pixelData[i + 1]; // G
105
+ imageData.data[dataIndex + 2] = pixelData[i + 2]; // B
106
+ imageData.data[dataIndex + 3] = 255; // A
107
+ }
108
+
109
+ ctx.putImageData(imageData, 0, 0);
110
+ };
111
+
112
+ const handleDownload = () => {
113
+ if (!canvasRef.current) return;
114
+
115
+ const link = document.createElement('a');
116
+ link.download = `ray-tracing-token-${tokenIdInput}.png`;
117
+ link.href = canvasRef.current.toDataURL();
118
+ link.click();
119
+ };
120
+
121
+ return (
122
+ <Card>
123
+ <CardHeader>
124
+ <CardTitle>On-Chain Ray Tracing</CardTitle>
125
+ <CardDescription>
126
+ Render 32×32 3D image with full lighting calculation
127
+ </CardDescription>
128
+ </CardHeader>
129
+ <CardContent className="space-y-4">
130
+ {/* Token ID Input */}
131
+ <div className="space-y-2">
132
+ <Label htmlFor="token-id">Token ID to Render</Label>
133
+ <div className="flex gap-2">
134
+ <Input
135
+ id="token-id"
136
+ type="number"
137
+ placeholder="0"
138
+ value={tokenIdInput}
139
+ onChange={(e) => setTokenIdInput(e.target.value)}
140
+ disabled={isRendering}
141
+ />
142
+ <Button
143
+ onClick={handleRender}
144
+ disabled={!isNftConnected || !tokenIdInput || isRendering}
145
+ className="min-w-32"
146
+ >
147
+ {isRendering ? (
148
+ <>
149
+ <Loader2 className="h-4 w-4 mr-2 animate-spin" />
150
+ Rendering...
151
+ </>
152
+ ) : (
153
+ <>
154
+ <ImageIcon className="h-4 w-4 mr-2" />
155
+ Render
156
+ </>
157
+ )}
158
+ </Button>
159
+ </div>
160
+ <p className="text-xs text-muted-foreground">
161
+ {mintedTokenId !== null
162
+ ? `Your minted token: ${mintedTokenId.toString()}`
163
+ : 'Enter any valid token ID to render'
164
+ }
165
+ </p>
166
+ </div>
167
+
168
+ {/* Gas Estimate */}
169
+ {gasUsed && (
170
+ <div className="bg-muted p-3 rounded-md text-xs">
171
+ <div className="flex justify-between">
172
+ <span className="text-muted-foreground">Estimated Gas:</span>
173
+ <span className="font-mono">{Number(gasUsed).toLocaleString()}</span>
174
+ </div>
175
+ <div className="flex justify-between mt-1">
176
+ <span className="text-muted-foreground">Est. Cost:</span>
177
+ <span className="font-mono">~${(Number(gasUsed) * 0.02 / 1e9 * 2500).toFixed(4)}</span>
178
+ </div>
179
+ </div>
180
+ )}
181
+
182
+ {/* Canvas Display */}
183
+ {renderedData ? (
184
+ <div className="space-y-3">
185
+ <div className="flex items-center justify-center bg-muted rounded-md p-4">
186
+ <canvas
187
+ ref={canvasRef}
188
+ className="border border-border rounded-md"
189
+ style={{
190
+ imageRendering: 'pixelated',
191
+ width: '256px',
192
+ height: '256px',
193
+ }}
194
+ />
195
+ </div>
196
+
197
+ {/* Render Info */}
198
+ <div className="bg-green-500/10 border border-green-500/20 p-3 rounded-md text-xs space-y-1">
199
+ <h4 className="font-semibold text-green-400">✓ Rendered On-Chain</h4>
200
+ <div className="flex justify-between">
201
+ <span className="text-muted-foreground">Resolution:</span>
202
+ <span>32×32 pixels</span>
203
+ </div>
204
+ <div className="flex justify-between">
205
+ <span className="text-muted-foreground">Data Size:</span>
206
+ <span>{renderedData.length.toLocaleString()} bytes</span>
207
+ </div>
208
+ <div className="flex justify-between">
209
+ <span className="text-muted-foreground">Algorithm:</span>
210
+ <span>Ray-sphere intersection + diffuse lighting</span>
211
+ </div>
212
+ </div>
213
+
214
+ {/* Download Button */}
215
+ <Button
216
+ onClick={handleDownload}
217
+ variant="outline"
218
+ className="w-full"
219
+ size="sm"
220
+ >
221
+ <Download className="h-4 w-4 mr-2" />
222
+ Download 32×32 PNG
223
+ </Button>
224
+ </div>
225
+ ) : (
226
+ <div className="flex items-center justify-center h-64 border border-border rounded-md bg-muted">
227
+ <div className="text-center text-muted-foreground">
228
+ <ImageIcon className="h-12 w-12 mx-auto mb-3 opacity-50" />
229
+ <p className="text-sm">Render a token to see the result</p>
230
+ </div>
231
+ </div>
232
+ )}
233
+
234
+ {/* Error Display */}
235
+ {renderError && (
236
+ <div className="bg-red-500/10 border border-red-500/20 p-3 rounded-md text-sm text-red-400">
237
+ <p className="font-medium">Rendering Failed</p>
238
+ <p className="text-xs mt-1">{renderError}</p>
239
+ </div>
240
+ )}
241
+
242
+ {/* Info Box */}
243
+ <div className="bg-blue-500/10 border border-blue-500/20 p-3 rounded-md text-xs text-blue-400">
244
+ <p className="font-medium mb-1">🔬 What Happens:</p>
245
+ <ul className="space-y-1">
246
+ <li>• Contract loads 21-byte config from storage</li>
247
+ <li>• For each of 1,024 pixels:</li>
248
+ <li className="pl-4">→ Generate ray from camera</li>
249
+ <li className="pl-4">→ Check sphere intersection (quadratic equation)</li>
250
+ <li className="pl-4">→ Calculate lighting (dot product)</li>
251
+ <li className="pl-4">→ Store RGB value</li>
252
+ <li>• Returns 3,072 bytes (32×32×3 RGB)</li>
253
+ <li>• 100% deterministic - same input = same output</li>
254
+ </ul>
255
+ </div>
256
+ </CardContent>
257
+ </Card>
258
+ );
259
+ }
@@ -0,0 +1,217 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { Button } from '@/components/ui/button';
5
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
6
+ import { Label } from '@/components/ui/label';
7
+ import { Slider } from '@/components/ui/slider';
8
+ import { Loader2, Sparkles } from 'lucide-react';
9
+ import { usePublicClient } from 'wagmi';
10
+ import { arbitrumSepolia } from 'wagmi/chains';
11
+ import { MNN_ABI } from '@/lib/ray-tracing-abi';
12
+
13
+ interface StyleControlsProps {
14
+ warmth: number;
15
+ setWarmth: (value: number) => void;
16
+ intensity: number;
17
+ setIntensity: (value: number) => void;
18
+ depth: number;
19
+ setDepth: (value: number) => void;
20
+ mnnAddress: string;
21
+ predictedColors: [number, number, number] | null;
22
+ setPredictedColors: (colors: [number, number, number] | null) => void;
23
+ }
24
+
25
+ export function StyleControls({
26
+ warmth,
27
+ setWarmth,
28
+ intensity,
29
+ setIntensity,
30
+ depth,
31
+ setDepth,
32
+ mnnAddress,
33
+ predictedColors,
34
+ setPredictedColors,
35
+ }: StyleControlsProps) {
36
+ const [isLoading, setIsLoading] = useState(false);
37
+ const publicClient = usePublicClient({ chainId: arbitrumSepolia.id });
38
+
39
+ const handlePreview = async () => {
40
+ if (!publicClient) return;
41
+
42
+ setIsLoading(true);
43
+
44
+ try {
45
+ // Convert 0-100 to 0-10^18 scale
46
+ const warmthScaled = BigInt(Math.floor((warmth / 100) * 1e18));
47
+ const intensityScaled = BigInt(Math.floor((intensity / 100) * 1e18));
48
+ const depthScaled = BigInt(Math.floor((depth / 100) * 1e18));
49
+
50
+ const result = await publicClient.readContract({
51
+ address: mnnAddress as `0x${string}`,
52
+ abi: MNN_ABI as any,
53
+ functionName: 'viewAesthetic', // Changed from view_aesthetic
54
+ args: [warmthScaled, intensityScaled, depthScaled],
55
+ });
56
+
57
+ const [r, g, b] = result as [number, number, number];
58
+ setPredictedColors([r, g, b]);
59
+ } catch (error) {
60
+ console.error('Preview failed:', error);
61
+ alert('Failed to preview colors. Check contract connection.');
62
+ } finally {
63
+ setIsLoading(false);
64
+ }
65
+ };
66
+
67
+ return (
68
+ <Card>
69
+ <CardHeader>
70
+ <CardTitle>Style Parameters</CardTitle>
71
+ <CardDescription>
72
+ Adjust aesthetic parameters for neural network prediction
73
+ </CardDescription>
74
+ </CardHeader>
75
+ <CardContent className="space-y-4">
76
+ {/* Warmth Slider */}
77
+ <div className="space-y-2">
78
+ <div className="flex items-center justify-between">
79
+ <Label>Warmth</Label>
80
+ <span className="text-sm text-muted-foreground">{warmth}%</span>
81
+ </div>
82
+ <Slider
83
+ value={[warmth]}
84
+ onValueChange={(value) => setWarmth(value[0])}
85
+ min={0}
86
+ max={100}
87
+ step={1}
88
+ className="w-full"
89
+ />
90
+ <p className="text-xs text-muted-foreground">
91
+ Cool tones (0%) to warm tones (100%)
92
+ </p>
93
+ </div>
94
+
95
+ {/* Intensity Slider */}
96
+ <div className="space-y-2">
97
+ <div className="flex items-center justify-between">
98
+ <Label>Intensity</Label>
99
+ <span className="text-sm text-muted-foreground">{intensity}%</span>
100
+ </div>
101
+ <Slider
102
+ value={[intensity]}
103
+ onValueChange={(value) => setIntensity(value[0])}
104
+ min={0}
105
+ max={100}
106
+ step={1}
107
+ className="w-full"
108
+ />
109
+ <p className="text-xs text-muted-foreground">
110
+ Subtle (0%) to vibrant (100%)
111
+ </p>
112
+ </div>
113
+
114
+ {/* Depth Slider */}
115
+ <div className="space-y-2">
116
+ <div className="flex items-center justify-between">
117
+ <Label>Depth</Label>
118
+ <span className="text-sm text-muted-foreground">{depth}%</span>
119
+ </div>
120
+ <Slider
121
+ value={[depth]}
122
+ onValueChange={(value) => setDepth(value[0])}
123
+ min={0}
124
+ max={100}
125
+ step={1}
126
+ className="w-full"
127
+ />
128
+ <p className="text-xs text-muted-foreground">
129
+ Flat (0%) to dimensional (100%)
130
+ </p>
131
+ </div>
132
+
133
+ {/* Preview Button */}
134
+ <Button
135
+ onClick={handlePreview}
136
+ disabled={isLoading}
137
+ className="w-full"
138
+ size="lg"
139
+ >
140
+ {isLoading ? (
141
+ <>
142
+ <Loader2 className="h-4 w-4 mr-2 animate-spin" />
143
+ Predicting...
144
+ </>
145
+ ) : (
146
+ <>
147
+ <Sparkles className="h-4 w-4 mr-2" />
148
+ Preview Colors (FREE)
149
+ </>
150
+ )}
151
+ </Button>
152
+
153
+ {/* Predicted Colors Display */}
154
+ {predictedColors && (
155
+ <div className="space-y-3">
156
+ <div className="bg-green-500/10 border border-green-500/20 p-3 rounded-md">
157
+ <h4 className="text-sm font-semibold text-green-400 mb-3">✓ Neural Network Prediction</h4>
158
+ <div className="flex items-center gap-3">
159
+ <div
160
+ className="w-20 h-20 rounded-md border-2 border-green-500/50 shadow-lg"
161
+ style={{
162
+ backgroundColor: `rgb(${predictedColors[0]}, ${predictedColors[1]}, ${predictedColors[2]})`,
163
+ }}
164
+ />
165
+ <div className="flex-1 space-y-2">
166
+ <div className="flex justify-between items-center">
167
+ <span className="text-xs text-muted-foreground">Red</span>
168
+ <div className="flex items-center gap-2">
169
+ <div
170
+ className="w-12 h-3 rounded-sm border border-border"
171
+ style={{ backgroundColor: `rgb(${predictedColors[0]}, 0, 0)` }}
172
+ />
173
+ <span className="font-mono text-xs w-8">{predictedColors[0]}</span>
174
+ </div>
175
+ </div>
176
+ <div className="flex justify-between items-center">
177
+ <span className="text-xs text-muted-foreground">Green</span>
178
+ <div className="flex items-center gap-2">
179
+ <div
180
+ className="w-12 h-3 rounded-sm border border-border"
181
+ style={{ backgroundColor: `rgb(0, ${predictedColors[1]}, 0)` }}
182
+ />
183
+ <span className="font-mono text-xs w-8">{predictedColors[1]}</span>
184
+ </div>
185
+ </div>
186
+ <div className="flex justify-between items-center">
187
+ <span className="text-xs text-muted-foreground">Blue</span>
188
+ <div className="flex items-center gap-2">
189
+ <div
190
+ className="w-12 h-3 rounded-sm border border-border"
191
+ style={{ backgroundColor: `rgb(0, 0, ${predictedColors[2]})` }}
192
+ />
193
+ <span className="font-mono text-xs w-8">{predictedColors[2]}</span>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ </div>
198
+ <p className="text-xs text-green-400 mt-3 flex items-center gap-1">
199
+ <Sparkles className="h-3 w-3" />
200
+ Computed on-chain with 0 gas cost (VIEW function)
201
+ </p>
202
+ </div>
203
+ </div>
204
+ )}
205
+
206
+ {/* Info Box */}
207
+ <div className="bg-blue-500/10 border border-blue-500/20 p-3 rounded-md text-xs text-blue-400">
208
+ <p className="font-medium mb-1">💡 How It Works:</p>
209
+ <p>
210
+ The Mini Neural Network (3→4→2 architecture) runs entirely on-chain as a VIEW function.
211
+ It predicts aesthetic RGB colors based on your style parameters - completely free!
212
+ </p>
213
+ </div>
214
+ </CardContent>
215
+ </Card>
216
+ );
217
+ }