diff --git a/README.md b/README.md index 9ac25817..3b1d2827 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ [![Bolt.new: AI-Powered Full-Stack Web Development in the Browser](./public/social_preview_index.jpg)](https://bolt.new) -# Bolt.new Fork by Cole Medin - oTToDev +# Bolt.diy (Previously oTToDev) -This fork of Bolt.new (oTToDev) allows you to choose the LLM that you use for each prompt! Currently, you can use OpenAI, Anthropic, Ollama, OpenRouter, Gemini, LMStudio, Mistral, xAI, HuggingFace, DeepSeek, or Groq models - and it is easily extended to use any other model supported by the Vercel AI SDK! See the instructions below for running this locally and extending it to include more models. +Welcome to Bolt.diy, the official open source version of Bolt.new (previously known as oTToDev and Bolt.new ANY LLM), which allows you to choose the LLM that you use for each prompt! Currently, you can use OpenAI, Anthropic, Ollama, OpenRouter, Gemini, LMStudio, Mistral, xAI, HuggingFace, DeepSeek, or Groq models - and it is easily extended to use any other model supported by the Vercel AI SDK! See the instructions below for running this locally and extending it to include more models. -Check the [oTToDev Docs](https://coleam00.github.io/bolt.new-any-llm/) for more information. +Check the [Bolt.diy Docs](https://stackblitz-labs.github.io/bolt.diy/) for more information. This documentation is still being updated after the transfer. -## Join the community for oTToDev! +Bolt.diy was originally started by [Cole Medin](https://www.youtube.com/@ColeMedin) but has quickly grown into a massive community effort to build the BEST open source AI coding assistant! + +## Join the community for Bolt.diy! https://thinktank.ottomator.ai @@ -56,7 +58,7 @@ https://thinktank.ottomator.ai ## Bolt.new: AI-Powered Full-Stack Web Development in the Browser -Bolt.new is an AI-powered web development agent that allows you to prompt, run, edit, and deploy full-stack applications directly from your browser—no local setup required. If you're here to build your own AI-powered web dev agent using the Bolt open source codebase, [click here to get started!](./CONTRIBUTING.md) +Bolt.new (and by extension Bolt.diy) is an AI-powered web development agent that allows you to prompt, run, edit, and deploy full-stack applications directly from your browser—no local setup required. If you're here to build your own AI-powered web dev agent using the Bolt open source codebase, [click here to get started!](./CONTRIBUTING.md) ## What Makes Bolt.new Different @@ -96,7 +98,7 @@ If you see usr/local/bin in the output then you're good to go. 3. Clone the repository (if you haven't already) by opening a Terminal window (or CMD with admin permissions) and then typing in this: ``` -git clone https://github.com/coleam00/bolt.new-any-llm.git +git clone https://github.com/stackblitz-labs/bolt.diy.git ``` 3. Rename .env.example to .env.local and add your LLM API keys. You will find this file on a Mac at "[your name]/bold.new-any-llm/.env.example". For Windows and Linux the path will be similar. @@ -225,11 +227,11 @@ pnpm run dev This will start the Remix Vite development server. You will need Google Chrome Canary to run this locally if you use Chrome! It's an easy install and a good browser for web development anyway. -## How do I contribute to oTToDev? +## How do I contribute to Bolt.diy? -[Please check out our dedicated page for contributing to oTToDev here!](CONTRIBUTING.md) +[Please check out our dedicated page for contributing to Bolt.diy here!](CONTRIBUTING.md) -## What are the future plans for oTToDev? +## What are the future plans for Bolt.diy? [Check out our Roadmap here!](https://roadmap.sh/r/ottodev-roadmap-2ovzo) @@ -237,4 +239,4 @@ Lot more updates to this roadmap coming soon! ## FAQ -[Please check out our dedicated page for FAQ's related to oTToDev here!](FAQ.md) +[Please check out our dedicated page for FAQ's related to Bolt.diy here!](FAQ.md) diff --git a/app/commit.json b/app/commit.json index 7ed2c7df..32c08421 100644 --- a/app/commit.json +++ b/app/commit.json @@ -1 +1 @@ -{ "commit": "eddf5603c3865536f96774fc3358cf24760fb613" } +{ "commit": "fd2c17c384a69ab5e7a40113342caa7de405b944" } diff --git a/app/components/chat/BaseChat.module.scss b/app/components/chat/BaseChat.module.scss index cf530a11..4908e34e 100644 --- a/app/components/chat/BaseChat.module.scss +++ b/app/components/chat/BaseChat.module.scss @@ -18,82 +18,6 @@ opacity: 1; } -.RayContainer { - --gradient-opacity: 0.85; - --ray-gradient: radial-gradient(rgba(83, 196, 255, var(--gradient-opacity)) 0%, rgba(43, 166, 255, 0) 100%); - transition: opacity 0.25s linear; - position: fixed; - inset: 0; - pointer-events: none; - user-select: none; -} - -.LightRayOne { - width: 480px; - height: 680px; - transform: rotate(80deg); - top: -540px; - left: 250px; - filter: blur(110px); - position: absolute; - border-radius: 100%; - background: var(--ray-gradient); -} - -.LightRayTwo { - width: 110px; - height: 400px; - transform: rotate(-20deg); - top: -280px; - left: 350px; - mix-blend-mode: overlay; - opacity: 0.6; - filter: blur(60px); - position: absolute; - border-radius: 100%; - background: var(--ray-gradient); -} - -.LightRayThree { - width: 400px; - height: 370px; - top: -350px; - left: 200px; - mix-blend-mode: overlay; - opacity: 0.6; - filter: blur(21px); - position: absolute; - border-radius: 100%; - background: var(--ray-gradient); -} - -.LightRayFour { - position: absolute; - width: 330px; - height: 370px; - top: -330px; - left: 50px; - mix-blend-mode: overlay; - opacity: 0.5; - filter: blur(21px); - border-radius: 100%; - background: var(--ray-gradient); -} - -.LightRayFive { - position: absolute; - width: 110px; - height: 400px; - transform: rotate(-40deg); - top: -280px; - left: -10px; - mix-blend-mode: overlay; - opacity: 0.8; - filter: blur(60px); - border-radius: 100%; - background: var(--ray-gradient); -} - .PromptEffectContainer { --prompt-container-offset: 50px; --prompt-line-stroke-width: 1px; diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index b17baf95..a77932c7 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -110,8 +110,10 @@ export const BaseChat = React.forwardRef( const [recognition, setRecognition] = useState(null); const [transcript, setTranscript] = useState(''); - // Update enabled providers when cookies change - console.log(transcript); + useEffect(() => { + console.log(transcript); + }, [transcript]); + useEffect(() => { // Load API keys from cookies on component mount try { @@ -274,19 +276,9 @@ export const BaseChat = React.forwardRef( const baseChat = (
-
-
-
-
-
-
-
{() => }
@@ -336,15 +328,15 @@ export const BaseChat = React.forwardRef( gradientUnits="userSpaceOnUse" gradientTransform="rotate(-45)" > - - - - + + + + - - + + diff --git a/app/components/chat/ModelSelector.tsx b/app/components/chat/ModelSelector.tsx index 435f4bab..bd41eb4d 100644 --- a/app/components/chat/ModelSelector.tsx +++ b/app/components/chat/ModelSelector.tsx @@ -121,8 +121,8 @@ export const ModelSelector = ({ > {[...modelList] .filter((e) => e.provider == provider?.name && e.name) - .map((modelOption) => ( - ))} diff --git a/app/components/header/Header.tsx b/app/components/header/Header.tsx index 8b2e81f7..ce46702a 100644 --- a/app/components/header/Header.tsx +++ b/app/components/header/Header.tsx @@ -10,18 +10,17 @@ export function Header() { return (
{chat.started && ( // Display ChatDescription and HeaderActionButtons only when the chat has started. diff --git a/app/components/settings/Settings.module.scss b/app/components/settings/Settings.module.scss index 6da82882..639cbbc5 100644 --- a/app/components/settings/Settings.module.scss +++ b/app/components/settings/Settings.module.scss @@ -46,7 +46,7 @@ padding: 1rem; margin-bottom: 1rem; border-style: solid; - border-color: var(--bolt-elements-button-danger-backgroundHover) ; + border-color: var(--bolt-elements-button-danger-backgroundHover); border-width: thin; button { @@ -60,4 +60,4 @@ background-color: var(--bolt-elements-button-danger-backgroundHover); } } -} \ No newline at end of file +} diff --git a/app/components/settings/SettingsWindow.tsx b/app/components/settings/SettingsWindow.tsx index 8ae4a484..b7b368d6 100644 --- a/app/components/settings/SettingsWindow.tsx +++ b/app/components/settings/SettingsWindow.tsx @@ -83,7 +83,7 @@ export const SettingsWindow = ({ open, onClose }: SettingsProps) => { ))}
{ GitHub { + return ( +
+
+
+
+
+
+
+
+
+
+ ); +}; + +export default BackgroundRays; diff --git a/app/components/ui/BackgroundRays/styles.module.scss b/app/components/ui/BackgroundRays/styles.module.scss new file mode 100644 index 00000000..bac4c8aa --- /dev/null +++ b/app/components/ui/BackgroundRays/styles.module.scss @@ -0,0 +1,246 @@ +.rayContainer { + // Theme-specific colors + --ray-color-primary: color-mix(in srgb, var(--primary-color), transparent 30%); + --ray-color-secondary: color-mix(in srgb, var(--secondary-color), transparent 30%); + --ray-color-accent: color-mix(in srgb, var(--accent-color), transparent 30%); + + // Theme-specific gradients + --ray-gradient-primary: radial-gradient(var(--ray-color-primary) 0%, transparent 70%); + --ray-gradient-secondary: radial-gradient(var(--ray-color-secondary) 0%, transparent 70%); + --ray-gradient-accent: radial-gradient(var(--ray-color-accent) 0%, transparent 70%); + + position: fixed; + inset: 0; + overflow: hidden; + animation: fadeIn 1.5s ease-out; + pointer-events: none; + z-index: 0; + // background-color: transparent; + + :global(html[data-theme='dark']) & { + mix-blend-mode: screen; + } + + :global(html[data-theme='light']) & { + mix-blend-mode: multiply; + } +} + +.lightRay { + position: absolute; + border-radius: 100%; + + :global(html[data-theme='dark']) & { + mix-blend-mode: screen; + } + + :global(html[data-theme='light']) & { + mix-blend-mode: multiply; + opacity: 0.4; + } +} + +.ray1 { + width: 600px; + height: 800px; + background: var(--ray-gradient-primary); + transform: rotate(65deg); + top: -500px; + left: -100px; + filter: blur(80px); + opacity: 0.6; + animation: float1 15s infinite ease-in-out; +} + +.ray2 { + width: 400px; + height: 600px; + background: var(--ray-gradient-secondary); + transform: rotate(-30deg); + top: -300px; + left: 200px; + filter: blur(60px); + opacity: 0.6; + animation: float2 18s infinite ease-in-out; +} + +.ray3 { + width: 500px; + height: 400px; + background: var(--ray-gradient-accent); + top: -320px; + left: 500px; + filter: blur(65px); + opacity: 0.5; + animation: float3 20s infinite ease-in-out; +} + +.ray4 { + width: 400px; + height: 450px; + background: var(--ray-gradient-secondary); + top: -350px; + left: 800px; + filter: blur(55px); + opacity: 0.55; + animation: float4 17s infinite ease-in-out; +} + +.ray5 { + width: 350px; + height: 500px; + background: var(--ray-gradient-primary); + transform: rotate(-45deg); + top: -250px; + left: 1000px; + filter: blur(45px); + opacity: 0.6; + animation: float5 16s infinite ease-in-out; +} + +.ray6 { + width: 300px; + height: 700px; + background: var(--ray-gradient-accent); + transform: rotate(75deg); + top: -400px; + left: 600px; + filter: blur(75px); + opacity: 0.45; + animation: float6 19s infinite ease-in-out; +} + +.ray7 { + width: 450px; + height: 600px; + background: var(--ray-gradient-primary); + transform: rotate(45deg); + top: -450px; + left: 350px; + filter: blur(65px); + opacity: 0.55; + animation: float7 21s infinite ease-in-out; +} + +.ray8 { + width: 380px; + height: 550px; + background: var(--ray-gradient-secondary); + transform: rotate(-60deg); + top: -380px; + left: 750px; + filter: blur(58px); + opacity: 0.6; + animation: float8 14s infinite ease-in-out; +} + +@keyframes float1 { + 0%, + 100% { + transform: rotate(65deg) translate(0, 0); + } + 25% { + transform: rotate(70deg) translate(30px, 20px); + } + 50% { + transform: rotate(60deg) translate(-20px, 40px); + } + 75% { + transform: rotate(68deg) translate(-40px, 10px); + } +} + +@keyframes float2 { + 0%, + 100% { + transform: rotate(-30deg) scale(1); + } + 33% { + transform: rotate(-25deg) scale(1.1); + } + 66% { + transform: rotate(-35deg) scale(0.95); + } +} + +@keyframes float3 { + 0%, + 100% { + transform: translate(0, 0) rotate(0deg); + } + 25% { + transform: translate(40px, 20px) rotate(5deg); + } + 75% { + transform: translate(-30px, 40px) rotate(-5deg); + } +} + +@keyframes float4 { + 0%, + 100% { + transform: scale(1) rotate(0deg); + } + 50% { + transform: scale(1.15) rotate(10deg); + } +} + +@keyframes float5 { + 0%, + 100% { + transform: rotate(-45deg) translate(0, 0); + } + 33% { + transform: rotate(-40deg) translate(25px, -20px); + } + 66% { + transform: rotate(-50deg) translate(-25px, 20px); + } +} + +@keyframes float6 { + 0%, + 100% { + transform: rotate(75deg) scale(1); + filter: blur(75px); + } + 50% { + transform: rotate(85deg) scale(1.1); + filter: blur(65px); + } +} + +@keyframes float7 { + 0%, + 100% { + transform: rotate(45deg) translate(0, 0); + opacity: 0.55; + } + 50% { + transform: rotate(40deg) translate(-30px, 30px); + opacity: 0.65; + } +} + +@keyframes float8 { + 0%, + 100% { + transform: rotate(-60deg) scale(1); + } + 25% { + transform: rotate(-55deg) scale(1.05); + } + 75% { + transform: rotate(-65deg) scale(0.95); + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index 86d73409..dc1c8358 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -3,6 +3,7 @@ import { ClientOnly } from 'remix-utils/client-only'; import { BaseChat } from '~/components/chat/BaseChat'; import { Chat } from '~/components/chat/Chat.client'; import { Header } from '~/components/header/Header'; +import BackgroundRays from '~/components/ui/BackgroundRays'; export const meta: MetaFunction = () => { return [{ title: 'Bolt' }, { name: 'description', content: 'Talk with Bolt, an AI assistant from StackBlitz' }]; @@ -12,7 +13,8 @@ export const loader = () => json({}); export default function Index() { return ( -
+
+
}>{() => }
diff --git a/app/styles/index.scss b/app/styles/index.scss index 36ebac2c..91a4cf84 100644 --- a/app/styles/index.scss +++ b/app/styles/index.scss @@ -12,3 +12,13 @@ body { height: 100%; width: 100%; } + +:root { + --gradient-opacity: 0.8; + --primary-color: rgba(158, 117, 240, var(--gradient-opacity)); + --secondary-color: rgba(138, 43, 226, var(--gradient-opacity)); + --accent-color: rgba(128, 59, 239, var(--gradient-opacity)); + // --primary-color: rgba(147, 112, 219, var(--gradient-opacity)); + // --secondary-color: rgba(138, 43, 226, var(--gradient-opacity)); + // --accent-color: rgba(180, 170, 220, var(--gradient-opacity)); +} diff --git a/app/utils/constants.ts b/app/utils/constants.ts index ffedee6c..9d987745 100644 --- a/app/utils/constants.ts +++ b/app/utils/constants.ts @@ -1,6 +1,7 @@ import Cookies from 'js-cookie'; import type { ModelInfo, OllamaApiResponse, OllamaModel } from './types'; import type { ProviderInfo, IProviderSetting } from '~/types/model'; +import { createScopedLogger } from './logger'; export const WORK_DIR_NAME = 'project'; export const WORK_DIR = `/home/${WORK_DIR_NAME}`; @@ -10,6 +11,8 @@ export const PROVIDER_REGEX = /\[Provider: (.*?)\]\n\n/; export const DEFAULT_MODEL = 'claude-3-5-sonnet-latest'; export const PROMPT_COOKIE_KEY = 'cachedPrompt'; +const logger = createScopedLogger('Constants'); + const PROVIDER_LIST: ProviderInfo[] = [ { name: 'Anthropic', @@ -386,8 +389,8 @@ async function getOllamaModels(apiKeys?: Record, settings?: IPro provider: 'Ollama', maxTokenAllowed: 8000, })); - } catch (e) { - console.error('Error getting Ollama models:', e); + } catch (e: any) { + logger.warn('Failed to get Ollama models: ', e.message || ''); return []; } } @@ -475,8 +478,8 @@ async function getLMStudioModels(_apiKeys?: Record, settings?: I label: model.id, provider: 'LMStudio', })); - } catch (e) { - console.error('Error getting LMStudio models:', e); + } catch (e: any) { + logger.warn('Failed to get LMStudio models: ', e.message || ''); return []; } } @@ -495,7 +498,7 @@ async function initializeModelList(providerSettings?: Record - + diff --git a/public/logo-dark-styled.png b/public/logo-dark-styled.png new file mode 100644 index 00000000..d410fe6e Binary files /dev/null and b/public/logo-dark-styled.png differ diff --git a/public/logo-dark.png b/public/logo-dark.png new file mode 100644 index 00000000..377fda33 Binary files /dev/null and b/public/logo-dark.png differ diff --git a/public/logo-light-styled.png b/public/logo-light-styled.png new file mode 100644 index 00000000..ef0af665 Binary files /dev/null and b/public/logo-light-styled.png differ diff --git a/public/logo-light.png b/public/logo-light.png new file mode 100644 index 00000000..6b4513ef Binary files /dev/null and b/public/logo-light.png differ diff --git a/public/logo.svg b/public/logo.svg index 58d6874c..d3ae1ba3 100644 --- a/public/logo.svg +++ b/public/logo.svg @@ -1 +1,15 @@ - + + + + + + + + + + + + + + + diff --git a/public/social_preview_index.jpg b/public/social_preview_index.jpg index 55952e32..2f226cb4 100644 Binary files a/public/social_preview_index.jpg and b/public/social_preview_index.jpg differ diff --git a/uno.config.ts b/uno.config.ts index 503e1af6..24019911 100644 --- a/uno.config.ts +++ b/uno.config.ts @@ -35,17 +35,17 @@ const BASE_COLORS = { 950: '#0A0A0A', }, accent: { - 50: '#EEF9FF', - 100: '#D8F1FF', - 200: '#BAE7FF', - 300: '#8ADAFF', - 400: '#53C4FF', - 500: '#2BA6FF', - 600: '#1488FC', - 700: '#0D6FE8', - 800: '#1259BB', - 900: '#154E93', - 950: '#122F59', + 50: '#F8F5FF', + 100: '#F0EBFF', + 200: '#E1D6FF', + 300: '#CEBEFF', + 400: '#B69EFF', + 500: '#9C7DFF', + 600: '#8A5FFF', + 700: '#7645E8', + 800: '#6234BB', + 900: '#502D93', + 950: '#2D1959', }, green: { 50: '#F0FDF4',