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.
- package/Readme.MD +1515 -0
- package/cli.js +28 -0
- package/frontend/.vscode/settings.json +9 -0
- package/frontend/app/api/chat/route.ts +101 -0
- package/frontend/app/api/check-setup/route.ts +93 -0
- package/frontend/app/api/cleanup/route.ts +14 -0
- package/frontend/app/api/compile/route.ts +95 -0
- package/frontend/app/api/compile-stream/route.ts +98 -0
- package/frontend/app/api/complete/route.ts +86 -0
- package/frontend/app/api/deploy/route.ts +118 -0
- package/frontend/app/api/export-abi/route.ts +58 -0
- package/frontend/app/favicon.ico +0 -0
- package/frontend/app/globals.css +177 -0
- package/frontend/app/layout.tsx +29 -0
- package/frontend/app/ml/page.tsx +694 -0
- package/frontend/app/page.tsx +1132 -0
- package/frontend/app/providers.tsx +18 -0
- package/frontend/app/qlearning/page.tsx +188 -0
- package/frontend/app/raytracing/page.tsx +268 -0
- package/frontend/components/abi/ABIDialog.tsx +132 -0
- package/frontend/components/ai/AICompletionPopup.tsx +76 -0
- package/frontend/components/ai/ChatPanel.tsx +292 -0
- package/frontend/components/ai/QuickActions.tsx +128 -0
- package/frontend/components/blockchain/BlockchainContractBanner.tsx +64 -0
- package/frontend/components/blockchain/BlockchainLoadingDialog.tsx +188 -0
- package/frontend/components/deploy/DeployDialog.tsx +334 -0
- package/frontend/components/editor/FileTabs.tsx +181 -0
- package/frontend/components/editor/MonacoEditor.tsx +306 -0
- package/frontend/components/file-tree/ContextMenu.tsx +110 -0
- package/frontend/components/file-tree/DeleteConfirmDialog.tsx +61 -0
- package/frontend/components/file-tree/FileInputDialog.tsx +97 -0
- package/frontend/components/file-tree/FileNode.tsx +60 -0
- package/frontend/components/file-tree/FileTree.tsx +259 -0
- package/frontend/components/file-tree/FileTreeSkeleton.tsx +26 -0
- package/frontend/components/file-tree/FolderNode.tsx +105 -0
- package/frontend/components/github/GitHubLoadingDialog.tsx +201 -0
- package/frontend/components/github/GitHubMetadataBanner.tsx +61 -0
- package/frontend/components/github/LoadFromGitHubDialog.tsx +125 -0
- package/frontend/components/github/URLCopyButton.tsx +60 -0
- package/frontend/components/interact/ContractInteraction.tsx +323 -0
- package/frontend/components/interact/ContractPlaceholder.tsx +41 -0
- package/frontend/components/orbit/BenchmarkDialog.tsx +342 -0
- package/frontend/components/orbit/OrbitExplorer.tsx +273 -0
- package/frontend/components/project/ProjectActions.tsx +176 -0
- package/frontend/components/q-learning/ContractConfig.tsx +172 -0
- package/frontend/components/q-learning/MazeGrid.tsx +346 -0
- package/frontend/components/q-learning/PathAnimation.tsx +384 -0
- package/frontend/components/q-learning/QTableHeatmap.tsx +300 -0
- package/frontend/components/q-learning/TrainingForm.tsx +349 -0
- package/frontend/components/ray-tracing/ContractConfig.tsx +245 -0
- package/frontend/components/ray-tracing/MintingForm.tsx +280 -0
- package/frontend/components/ray-tracing/RenderCanvas.tsx +228 -0
- package/frontend/components/ray-tracing/RenderingPanel.tsx +259 -0
- package/frontend/components/ray-tracing/StyleControls.tsx +217 -0
- package/frontend/components/setup/SetupGuide.tsx +290 -0
- package/frontend/components/ui/KeyboardShortcutHint.tsx +74 -0
- package/frontend/components/ui/alert-dialog.tsx +157 -0
- package/frontend/components/ui/alert.tsx +66 -0
- package/frontend/components/ui/badge.tsx +46 -0
- package/frontend/components/ui/button.tsx +62 -0
- package/frontend/components/ui/card.tsx +92 -0
- package/frontend/components/ui/context-menu.tsx +252 -0
- package/frontend/components/ui/dialog.tsx +143 -0
- package/frontend/components/ui/dropdown-menu.tsx +257 -0
- package/frontend/components/ui/input.tsx +21 -0
- package/frontend/components/ui/label.tsx +24 -0
- package/frontend/components/ui/progress.tsx +31 -0
- package/frontend/components/ui/scroll-area.tsx +58 -0
- package/frontend/components/ui/select.tsx +190 -0
- package/frontend/components/ui/separator.tsx +28 -0
- package/frontend/components/ui/sheet.tsx +139 -0
- package/frontend/components/ui/skeleton.tsx +13 -0
- package/frontend/components/ui/slider.tsx +63 -0
- package/frontend/components/ui/sonner.tsx +40 -0
- package/frontend/components/ui/tabs.tsx +66 -0
- package/frontend/components/ui/textarea.tsx +18 -0
- package/frontend/components/wallet/ConnectButton.tsx +167 -0
- package/frontend/components/wallet/FaucetButton.tsx +256 -0
- package/frontend/components.json +22 -0
- package/frontend/eslint.config.mjs +18 -0
- package/frontend/hooks/useAICompletion.ts +75 -0
- package/frontend/hooks/useBlockchainLoader.ts +58 -0
- package/frontend/hooks/useChats.ts +137 -0
- package/frontend/hooks/useCompilation.ts +173 -0
- package/frontend/hooks/useFileTabs.ts +178 -0
- package/frontend/hooks/useGitHubLoader.ts +50 -0
- package/frontend/hooks/useKeyboardShortcuts.ts +47 -0
- package/frontend/hooks/usePanelState.ts +115 -0
- package/frontend/hooks/useProjectState.ts +276 -0
- package/frontend/hooks/useResponsive.ts +29 -0
- package/frontend/lib/abi-parser.ts +58 -0
- package/frontend/lib/blockchain-api.ts +374 -0
- package/frontend/lib/blockchain-explorers.ts +75 -0
- package/frontend/lib/blockchain-loader.ts +112 -0
- package/frontend/lib/cargo-template.ts +64 -0
- package/frontend/lib/compilation.ts +529 -0
- package/frontend/lib/constants.ts +31 -0
- package/frontend/lib/deployment.ts +176 -0
- package/frontend/lib/file-utils.ts +83 -0
- package/frontend/lib/github-api.ts +246 -0
- package/frontend/lib/github-loader.ts +369 -0
- package/frontend/lib/ml-contract-template.txt +900 -0
- package/frontend/lib/orbit-chains.ts +181 -0
- package/frontend/lib/output-formatter.ts +68 -0
- package/frontend/lib/project-manager.ts +632 -0
- package/frontend/lib/ray-tracing-abi.ts +206 -0
- package/frontend/lib/storage.ts +189 -0
- package/frontend/lib/templates.ts +1662 -0
- package/frontend/lib/url-parser.ts +188 -0
- package/frontend/lib/utils.ts +6 -0
- package/frontend/lib/wagmi-config.ts +24 -0
- package/frontend/next.config.ts +7 -0
- package/frontend/package-lock.json +16259 -0
- package/frontend/package.json +60 -0
- package/frontend/postcss.config.mjs +7 -0
- package/frontend/public/file.svg +1 -0
- package/frontend/public/globe.svg +1 -0
- package/frontend/public/ml-weights/.gitkeep +0 -0
- package/frontend/public/ml-weights/model.pkl +0 -0
- package/frontend/public/ml-weights/model_weights.json +27102 -0
- package/frontend/public/ml-weights/test_samples.json +7888 -0
- package/frontend/public/next.svg +1 -0
- package/frontend/public/vercel.svg +1 -0
- package/frontend/public/window.svg +1 -0
- package/frontend/scripts/check-env.js +52 -0
- package/frontend/scripts/setup.js +285 -0
- package/frontend/tailwind.config.ts +64 -0
- package/frontend/tsconfig.json +34 -0
- package/frontend/types/blockchain.ts +63 -0
- package/frontend/types/github.ts +54 -0
- package/frontend/types/project.ts +106 -0
- package/ml-training/README.md +56 -0
- package/ml-training/train_tiny_model.py +325 -0
- package/ml-training/update_template.py +59 -0
- 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
|
+
}
|