From a274262f3b2ae817ff4066a4f71a2ad7c0f88cd3 Mon Sep 17 00:00:00 2001
From: semantic-release-bot
Date: Wed, 4 Feb 2026 23:57:14 +0000
Subject: [PATCH 01/20] chore(release): 1.0.0-beta.14 [skip ci]
# [1.0.0-beta.14](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.13...v1.0.0-beta.14) (2026-02-04)
### Bug Fixes
* improve upload widget reliability and add video player poster options ([ac51e42](https://github.com/cloudinary-devs/create-cloudinary-react/commit/ac51e420f1b81f2a055bb3fb7e0331841e86b37a))
---
CHANGELOG.md | 7 +++++++
package.json | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3b89574..42c5220 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# [1.0.0-beta.14](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.13...v1.0.0-beta.14) (2026-02-04)
+
+
+### Bug Fixes
+
+* improve upload widget reliability and add video player poster options ([ac51e42](https://github.com/cloudinary-devs/create-cloudinary-react/commit/ac51e420f1b81f2a055bb3fb7e0331841e86b37a))
+
# [1.0.0-beta.13](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.12...v1.0.0-beta.13) (2026-02-03)
diff --git a/package.json b/package.json
index 59bff43..beb3b6f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.13",
+ "version": "1.0.0-beta.14",
"description": "Scaffold a Cloudinary React + Vite + TypeScript project with interactive setup",
"type": "module",
"bin": {
From 07a8a085686b160387388464a722d90c09cb6805 Mon Sep 17 00:00:00 2001
From: strausr
Date: Fri, 6 Feb 2026 08:22:12 -0800
Subject: [PATCH 02/20] fix: use correct CLAUDE.md convention for Claude Code
Changed from creating `.claude` and `claude.md` files to the official
`CLAUDE.md` convention as documented in Claude Code's official docs.
Co-authored-by: Cursor
---
cli.js | 3 +--
package-lock.json | 4 ++--
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/cli.js b/cli.js
index dda211c..82f1122 100755
--- a/cli.js
+++ b/cli.js
@@ -247,8 +247,7 @@ async function main() {
}
if (aiTools.includes('claude')) {
- writeFileSync(join(projectPath, '.claude'), aiRulesContent);
- writeFileSync(join(projectPath, 'claude.md'), aiRulesContent);
+ writeFileSync(join(projectPath, 'CLAUDE.md'), aiRulesContent);
}
if (aiTools.includes('generic')) {
diff --git a/package-lock.json b/package-lock.json
index 1d72ba9..9075b29 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.12",
+ "version": "1.0.0-beta.13",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.12",
+ "version": "1.0.0-beta.13",
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
From fecbe870decc54900cd9ba7fd8861eeeb5fa8f2e Mon Sep 17 00:00:00 2001
From: strausr
Date: Tue, 10 Feb 2026 12:58:34 -0800
Subject: [PATCH 03/20] Improve CLI and templates: README env default,
conditional upload widget, AI prompt context, save .env note
- README: default upload preset line when none supplied; add step to save .env and restart
- App: hide upload widget when no upload preset; conditional AI prompts (try uploading vs add preset)
- App: default display image to samples/landscapes/beach-boat
- CLI: explain AI assistant question (local instruction files); list created files per selection after create
- CLI: remove edit/review step and 'no data sent' line per feedback
- .cursorrules: save .env then restart for changes to load
Co-authored-by: Cursor
---
cli.js | 28 ++++++++++++++++++----
package-lock.json | 4 ++--
templates/.cursorrules.template | 2 +-
templates/README.md.template | 9 +++----
templates/src/App.tsx.template | 42 +++++++++++++++++++++++----------
5 files changed, 59 insertions(+), 26 deletions(-)
diff --git a/cli.js b/cli.js
index 82f1122..4d7243b 100755
--- a/cli.js
+++ b/cli.js
@@ -72,7 +72,7 @@ async function main() {
console.log(chalk.cyan.bold('\n🚀 Cloudinary React + Vite\n'));
console.log(chalk.gray('💡 Need a Cloudinary account? Sign up for free: https://cloudinary.com/users/register/free\n'));
- answers = await inquirer.prompt([
+ const questions = [
{
type: 'input',
name: 'projectName',
@@ -135,7 +135,9 @@ async function main() {
{
type: 'checkbox',
name: 'aiTools',
- message: 'Which AI coding assistant(s) are you using? (Select all that apply)',
+ message:
+ 'Which AI coding assistant(s) are you using? (Select all that apply)\n' +
+ chalk.gray(' We’ll add local instruction files so your assistant knows Cloudinary patterns.\n'),
choices: [
{ name: 'Cursor', value: 'cursor' },
{ name: 'GitHub Copilot', value: 'copilot' },
@@ -157,7 +159,9 @@ async function main() {
default: false,
when: (answers) => answers.installDeps,
},
- ]);
+ ];
+
+ answers = await inquirer.prompt(questions);
}
const { projectName, cloudName, uploadPreset, aiTools, installDeps, startDev } = answers;
@@ -183,6 +187,9 @@ async function main() {
PROJECT_NAME: projectName,
CLOUD_NAME: cloudName,
UPLOAD_PRESET: uploadPreset || '',
+ UPLOAD_PRESET_ENV_LINE: uploadPreset
+ ? `- \`VITE_CLOUDINARY_UPLOAD_PRESET\`: ${uploadPreset}`
+ : '- `VITE_CLOUDINARY_UPLOAD_PRESET`: (not set - add one for uploads)',
};
// Function to copy template file
@@ -278,6 +285,18 @@ async function main() {
console.log(chalk.green('✅ Project created successfully!\n'));
+ if (aiTools && aiTools.length > 0) {
+ console.log(chalk.cyan('📋 AI assistant files created:'));
+ if (aiTools.includes('cursor')) console.log(chalk.gray(' • Cursor: .cursorrules'));
+ if (aiTools.includes('copilot')) console.log(chalk.gray(' • GitHub Copilot: .github/copilot-instructions.md'));
+ if (aiTools.includes('claude')) console.log(chalk.gray(' • Claude: CLAUDE.md'));
+ if (aiTools.includes('generic')) console.log(chalk.gray(' • Generic: AI_INSTRUCTIONS.md, PROMPT.md'));
+ if (aiTools.includes('cursor') || aiTools.includes('claude')) {
+ console.log(chalk.gray(' • MCP (Cursor/Claude): .cursor/mcp.json'));
+ }
+ console.log('');
+ }
+
if (!answers.hasUploadPreset) {
console.log(chalk.yellow('\n📝 Note: Upload preset not configured'));
console.log(chalk.gray(' • Transformations will work with sample images'));
@@ -286,7 +305,8 @@ async function main() {
console.log(chalk.cyan(' 1. Go to https://console.cloudinary.com/app/settings/upload/presets'));
console.log(chalk.cyan(' 2. Click "Add upload preset"'));
console.log(chalk.cyan(' 3. Set it to "Unsigned" mode'));
- console.log(chalk.cyan(' 4. Add the preset name to your .env file\n'));
+ console.log(chalk.cyan(' 4. Add the preset name to your .env file'));
+ console.log(chalk.cyan(' 5. Save the file and restart the dev server so it loads correctly\n'));
}
if (installDeps) {
diff --git a/package-lock.json b/package-lock.json
index 9075b29..106a9b2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.13",
+ "version": "1.0.0-beta.14",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.13",
+ "version": "1.0.0-beta.14",
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
diff --git a/templates/.cursorrules.template b/templates/.cursorrules.template
index 2680dd0..0ae4eb3 100644
--- a/templates/.cursorrules.template
+++ b/templates/.cursorrules.template
@@ -30,7 +30,7 @@ If the user is **not** using the create-cloudinary-react CLI and only has these
Create a `.env` file in the project root with **Vite prefix** (required for client access):
- `VITE_CLOUDINARY_CLOUD_NAME=your_cloud_name` (required)
- `VITE_CLOUDINARY_UPLOAD_PRESET=your_unsigned_preset_name` (optional; required for unsigned upload widget)
-- Restart the dev server after adding or changing `.env`. Use `import.meta.env.VITE_*` in code, not `process.env`.
+- Save the `.env` file after editing it, then restart the dev server so changes load correctly. Use `import.meta.env.VITE_*` in code, not `process.env`.
**2. Reusable Cloudinary instance (config)**
Create a config file (e.g. `src/cloudinary/config.ts`) so the rest of the app can use a single `cld` instance:
diff --git a/templates/README.md.template b/templates/README.md.template
index 4faa69d..3cec979 100644
--- a/templates/README.md.template
+++ b/templates/README.md.template
@@ -18,11 +18,7 @@ This project uses Cloudinary for image management. If you don't have a Cloudinar
Your `.env` file has been pre-configured with:
- `VITE_CLOUDINARY_CLOUD_NAME`: {{CLOUD_NAME}}
-{{#UPLOAD_PRESET}}
-- `VITE_CLOUDINARY_UPLOAD_PRESET`: {{UPLOAD_PRESET}}
-{{/UPLOAD_PRESET}}
-{{^UPLOAD_PRESET}}
-- `VITE_CLOUDINARY_UPLOAD_PRESET`: (not set - required for uploads)
+{{UPLOAD_PRESET_ENV_LINE}}
**Note**: Transformations work without an upload preset (using sample images). Uploads require an unsigned upload preset.
@@ -31,7 +27,8 @@ To create an unsigned upload preset:
2. Click "Add upload preset"
3. Set it to "Unsigned" mode
4. Add the preset name to your `.env` file
-{{/UPLOAD_PRESET}}
+5. **Save** the `.env` file and restart the dev server so the new values load correctly.
+
## AI Assistant Support
diff --git a/templates/src/App.tsx.template b/templates/src/App.tsx.template
index 7bde6c9..3989371 100644
--- a/templates/src/App.tsx.template
+++ b/templates/src/App.tsx.template
@@ -5,11 +5,13 @@ import { format, quality } from '@cloudinary/url-gen/actions/delivery';
import { auto } from '@cloudinary/url-gen/qualifiers/format';
import { auto as autoQuality } from '@cloudinary/url-gen/qualifiers/quality';
import { autoGravity } from '@cloudinary/url-gen/qualifiers/gravity';
-import { cld } from './cloudinary/config';
+import { cld, uploadPreset } from './cloudinary/config';
import { UploadWidget } from './cloudinary/UploadWidget';
import type { CloudinaryUploadResult } from './cloudinary/UploadWidget';
import './App.css';
+const hasUploadPreset = Boolean(uploadPreset);
+
function App() {
const [uploadedImageId, setUploadedImageId] = useState(null);
@@ -24,7 +26,7 @@ function App() {
};
// Display uploaded image if available, otherwise show a sample
- const imageId = uploadedImageId || 'samples/cloudinary-icon';
+ const imageId = uploadedImageId || 'samples/people/bicycle';
const displayImage = cld
.image(imageId)
@@ -38,14 +40,16 @@ function App() {
Cloudinary React + Vite
This is a ready-to-use development environment with Cloudinary integration.
-
-
Upload an Image
-
-
+ {hasUploadPreset && (
+
+
Upload an Image
+
+
+ )}
Display Image
@@ -66,9 +70,21 @@ function App() {
Copy and paste one of these prompts into your AI assistant:
- - Create an image gallery with lazy loading and responsive
- - Create a video player that plays a Cloudinary video
- - Add image overlays with text or logos
+ {hasUploadPreset ? (
+ <>
+ - Upload an image to my account
+ - Create an image gallery with lazy loading and responsive images
+ - Create a video player that plays a Cloudinary video
+ - Add image overlays with text or logos
+ >
+ ) : (
+ <>
+ - Let's try uploading — help me add an upload preset and upload widget
+ - Create an image gallery with lazy loading and responsive
+ - Create a video player that plays a Cloudinary video
+ - Add image overlays with text or logos
+ >
+ )}
From 1d7f0c6544f4e94d0c11d8033d46226186a5061c Mon Sep 17 00:00:00 2001
From: semantic-release-bot
Date: Tue, 10 Feb 2026 21:00:45 +0000
Subject: [PATCH 04/20] chore(release): 1.0.0-beta.15 [skip ci]
# [1.0.0-beta.15](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.14...v1.0.0-beta.15) (2026-02-10)
### Bug Fixes
* use correct CLAUDE.md convention for Claude Code ([07a8a08](https://github.com/cloudinary-devs/create-cloudinary-react/commit/07a8a085686b160387388464a722d90c09cb6805))
### Features
* **analytics:** add CLI feature detection for React SDK ([4dfe495](https://github.com/cloudinary-devs/create-cloudinary-react/commit/4dfe4957bf615e9df08afe729e4f024c02d1cc7f))
---
CHANGELOG.md | 12 ++++++++++++
package.json | 2 +-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 42c5220..b76300b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,15 @@
+# [1.0.0-beta.15](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.14...v1.0.0-beta.15) (2026-02-10)
+
+
+### Bug Fixes
+
+* use correct CLAUDE.md convention for Claude Code ([07a8a08](https://github.com/cloudinary-devs/create-cloudinary-react/commit/07a8a085686b160387388464a722d90c09cb6805))
+
+
+### Features
+
+* **analytics:** add CLI feature detection for React SDK ([4dfe495](https://github.com/cloudinary-devs/create-cloudinary-react/commit/4dfe4957bf615e9df08afe729e4f024c02d1cc7f))
+
# [1.0.0-beta.14](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.13...v1.0.0-beta.14) (2026-02-04)
diff --git a/package.json b/package.json
index beb3b6f..9b18fb9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.14",
+ "version": "1.0.0-beta.15",
"description": "Scaffold a Cloudinary React + Vite + TypeScript project with interactive setup",
"type": "module",
"bin": {
From fbf01ae696e158cab48feb053a3515bb21453fdd Mon Sep 17 00:00:00 2001
From: strausr
Date: Tue, 10 Feb 2026 13:15:25 -0800
Subject: [PATCH 05/20] fix: remove upload question
---
templates/src/App.tsx.template | 1 -
1 file changed, 1 deletion(-)
diff --git a/templates/src/App.tsx.template b/templates/src/App.tsx.template
index 3989371..0955f76 100644
--- a/templates/src/App.tsx.template
+++ b/templates/src/App.tsx.template
@@ -72,7 +72,6 @@ function App() {
{hasUploadPreset ? (
<>
- - Upload an image to my account
- Create an image gallery with lazy loading and responsive images
- Create a video player that plays a Cloudinary video
- Add image overlays with text or logos
From d6c68ddc213fbc18771f26840f33edb805950799 Mon Sep 17 00:00:00 2001
From: eportis-cloudinary
Date: Tue, 10 Feb 2026 16:15:11 -0800
Subject: [PATCH 06/20] fix: complete the sentance
---
templates/src/App.tsx.template | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/templates/src/App.tsx.template b/templates/src/App.tsx.template
index 0955f76..ff03494 100644
--- a/templates/src/App.tsx.template
+++ b/templates/src/App.tsx.template
@@ -79,7 +79,7 @@ function App() {
) : (
<>
- Let's try uploading — help me add an upload preset and upload widget
- - Create an image gallery with lazy loading and responsive
+ - Create an image gallery with lazy loading and responsive images
- Create a video player that plays a Cloudinary video
- Add image overlays with text or logos
>
From a4ecf5d1d1478d854683a115735fa71f7fb50cea Mon Sep 17 00:00:00 2001
From: strausr
Date: Tue, 10 Feb 2026 17:34:45 -0800
Subject: [PATCH 07/20] fix: add copy on click
---
package-lock.json | 4 ++--
templates/src/App.css.template | 2 +-
templates/src/App.tsx.template | 19 ++++++++++++-------
3 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 106a9b2..c8d64fc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.14",
+ "version": "1.0.0-beta.15",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.14",
+ "version": "1.0.0-beta.15",
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
diff --git a/templates/src/App.css.template b/templates/src/App.css.template
index f16d21e..0daec37 100644
--- a/templates/src/App.css.template
+++ b/templates/src/App.css.template
@@ -90,7 +90,7 @@ h2 {
font-size: 0.9rem;
transition: all 0.2s;
user-select: text;
- cursor: text;
+ cursor: pointer;
}
.prompts-list li:hover {
diff --git a/templates/src/App.tsx.template b/templates/src/App.tsx.template
index ff03494..70e24f4 100644
--- a/templates/src/App.tsx.template
+++ b/templates/src/App.tsx.template
@@ -25,6 +25,11 @@ function App() {
alert(`Upload failed: ${error.message}`);
};
+ const copyPrompt = (e: React.MouseEvent) => {
+ const text = e.currentTarget.textContent ?? '';
+ void navigator.clipboard.writeText(text);
+ };
+
// Display uploaded image if available, otherwise show a sample
const imageId = uploadedImageId || 'samples/people/bicycle';
@@ -72,16 +77,16 @@ function App() {
{hasUploadPreset ? (
<>
- - Create an image gallery with lazy loading and responsive images
- - Create a video player that plays a Cloudinary video
- - Add image overlays with text or logos
+ - Create an image gallery with lazy loading and responsive images
+ - Create a video player that plays a Cloudinary video
+ - Add image overlays with text or logos
>
) : (
<>
- - Let's try uploading — help me add an upload preset and upload widget
- - Create an image gallery with lazy loading and responsive images
- - Create a video player that plays a Cloudinary video
- - Add image overlays with text or logos
+ - Let's try uploading — help me add an upload preset and upload widget
+ - Create an image gallery with lazy loading and responsive images
+ - Create a video player that plays a Cloudinary video
+ - Add image overlays with text or logos
>
)}
From d875b10b16a8734a27f8aff96eb981ef4fa10e7a Mon Sep 17 00:00:00 2001
From: semantic-release-bot
Date: Wed, 11 Feb 2026 01:36:53 +0000
Subject: [PATCH 08/20] chore(release): 1.0.0-beta.16 [skip ci]
# [1.0.0-beta.16](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.15...v1.0.0-beta.16) (2026-02-11)
### Bug Fixes
* add copy on click ([a4ecf5d](https://github.com/cloudinary-devs/create-cloudinary-react/commit/a4ecf5d1d1478d854683a115735fa71f7fb50cea))
* complete the sentance ([d6c68dd](https://github.com/cloudinary-devs/create-cloudinary-react/commit/d6c68ddc213fbc18771f26840f33edb805950799))
* remove upload question ([fbf01ae](https://github.com/cloudinary-devs/create-cloudinary-react/commit/fbf01ae696e158cab48feb053a3515bb21453fdd))
---
CHANGELOG.md | 9 +++++++++
package.json | 2 +-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b76300b..77dfb28 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+# [1.0.0-beta.16](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.15...v1.0.0-beta.16) (2026-02-11)
+
+
+### Bug Fixes
+
+* add copy on click ([a4ecf5d](https://github.com/cloudinary-devs/create-cloudinary-react/commit/a4ecf5d1d1478d854683a115735fa71f7fb50cea))
+* complete the sentance ([d6c68dd](https://github.com/cloudinary-devs/create-cloudinary-react/commit/d6c68ddc213fbc18771f26840f33edb805950799))
+* remove upload question ([fbf01ae](https://github.com/cloudinary-devs/create-cloudinary-react/commit/fbf01ae696e158cab48feb053a3515bb21453fdd))
+
# [1.0.0-beta.15](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.14...v1.0.0-beta.15) (2026-02-10)
diff --git a/package.json b/package.json
index 9b18fb9..076aef4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.15",
+ "version": "1.0.0-beta.16",
"description": "Scaffold a Cloudinary React + Vite + TypeScript project with interactive setup",
"type": "module",
"bin": {
From 9ad35b2351a69bca6d4dcd716b10a1508d5228a8 Mon Sep 17 00:00:00 2001
From: eportis-cloudinary
Date: Wed, 11 Feb 2026 13:04:12 -0800
Subject: [PATCH 09/20] feat: prompt copied animation
---
templates/src/App.css.template | 65 ++++++++++++++++++++++++++++++++++
templates/src/App.tsx.template | 26 +++++++++-----
2 files changed, 82 insertions(+), 9 deletions(-)
diff --git a/templates/src/App.css.template b/templates/src/App.css.template
index 0daec37..b3b36e9 100644
--- a/templates/src/App.css.template
+++ b/templates/src/App.css.template
@@ -91,6 +91,7 @@ h2 {
transition: all 0.2s;
user-select: text;
cursor: pointer;
+ position: relative;
}
.prompts-list li:hover {
@@ -98,3 +99,67 @@ h2 {
border-left-color: rgba(99, 102, 241, 0.8);
transform: translateX(4px);
}
+
+@keyframes wipe-in-out {
+ 0% {
+ clip-path: polygon(
+ 0% 0%,
+ 0% 100%,
+ 0% 100%,
+ 0% 0%
+ );
+ }
+ 15% {
+ clip-path: polygon(
+ 0% 0%,
+ 0% 100%,
+ 100% 100%,
+ 100% 0%
+ );
+ }
+ 85% {
+ clip-path: polygon(
+ 0% 0%,
+ 0% 100%,
+ 100% 100%,
+ 100% 0%
+ );
+ }
+ 100% {
+ clip-path: polygon(
+ 100% 0%,
+ 100% 100%,
+ 100% 100%,
+ 100% 0%
+ );
+ }
+}
+
+.prompts-list li::after {
+ content: '✓ copied';
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ background-color: green;
+ border-radius: 0.5rem;
+ visibility: hidden;
+ padding-top: 0.75em;
+ padding-left: 1em;
+
+ /* without this it sometimes glitched at the end? */
+ clip-path: polygon(
+ 0% 0%,
+ 0% 100%,
+ 0% 100%,
+ 0% 0%
+ );
+
+}
+
+.prompts-list li.clicked::after {
+ visibility: visible;
+ animation-duration: 1.5s;
+ animation-name: wipe-in-out;
+}
diff --git a/templates/src/App.tsx.template b/templates/src/App.tsx.template
index 70e24f4..1531daf 100644
--- a/templates/src/App.tsx.template
+++ b/templates/src/App.tsx.template
@@ -14,6 +14,7 @@ const hasUploadPreset = Boolean(uploadPreset);
function App() {
const [uploadedImageId, setUploadedImageId] = useState(null);
+ const [clickedIds, setClickedIds] = useState(new Set());
const handleUploadSuccess = (result: CloudinaryUploadResult) => {
console.log('Upload successful:', result);
@@ -25,9 +26,16 @@ function App() {
alert(`Upload failed: ${error.message}`);
};
- const copyPrompt = (e: React.MouseEvent) => {
+ const copyPrompt = (e: React.MouseEvent, id: number) => {
const text = e.currentTarget.textContent ?? '';
- void navigator.clipboard.writeText(text);
+ void navigator.clipboard.writeText(text).then(() => {
+ setClickedIds((prev) => new Set(prev).add(id));
+ setTimeout(() => setClickedIds( (prev) => {
+ const next = new Set(prev);
+ next.delete(id);
+ return next;
+ }), 2000);
+ });
};
// Display uploaded image if available, otherwise show a sample
@@ -77,16 +85,16 @@ function App() {
{hasUploadPreset ? (
<>
- - Create an image gallery with lazy loading and responsive images
- - Create a video player that plays a Cloudinary video
- - Add image overlays with text or logos
+ - copyPrompt(e, 0)} title="Click to copy" className={ clickedIds.has(0) ? "clicked" : '' }>Create an image gallery with lazy loading and responsive images
+ - copyPrompt(e, 1)} title="Click to copy" className={ clickedIds.has(1) ? "clicked" : '' }>Create a video player that plays a Cloudinary video
+ - copyPrompt(e, 2)} title="Click to copy" className={ clickedIds.has(2) ? "clicked" : '' }>Add image overlays with text or logos
>
) : (
<>
- - Let's try uploading — help me add an upload preset and upload widget
- - Create an image gallery with lazy loading and responsive images
- - Create a video player that plays a Cloudinary video
- - Add image overlays with text or logos
+ - copyPrompt(e, 0)} title="Click to copy" className={ clickedIds.has(0) ? "clicked" : '' }>Let's try uploading — help me add an upload preset and upload widget
+ - copyPrompt(e, 1)} title="Click to copy" className={ clickedIds.has(1) ? "clicked" : '' }>Create an image gallery with lazy loading and responsive images
+ - copyPrompt(e, 2)} title="Click to copy" className={ clickedIds.has(2) ? "clicked" : '' }>Create a video player that plays a Cloudinary video
+ - copyPrompt(e, 3)} title="Click to copy" className={ clickedIds.has(3) ? "clicked" : '' }>Add image overlays with text or logos
>
)}
From bade600ee63de7a7c3d8eec40569f8896f96a7bd Mon Sep 17 00:00:00 2001
From: strausr
Date: Wed, 11 Feb 2026 14:31:34 -0800
Subject: [PATCH 10/20] fix: simplified questions into arrays
---
templates/src/App.tsx.template | 40 +++++++++++++++++++---------------
1 file changed, 23 insertions(+), 17 deletions(-)
diff --git a/templates/src/App.tsx.template b/templates/src/App.tsx.template
index 1531daf..7fe7adc 100644
--- a/templates/src/App.tsx.template
+++ b/templates/src/App.tsx.template
@@ -12,9 +12,20 @@ import './App.css';
const hasUploadPreset = Boolean(uploadPreset);
+const PROMPTS_WITH_UPLOAD = [
+ 'Create an image gallery with lazy loading and responsive images',
+ 'Create a video player that plays a Cloudinary video',
+ 'Add image overlays with text or logos',
+];
+
+const PROMPTS_WITHOUT_UPLOAD = [
+ "Let's try uploading — help me add an upload preset and upload widget",
+ ...PROMPTS_WITH_UPLOAD,
+];
+
function App() {
const [uploadedImageId, setUploadedImageId] = useState(null);
- const [clickedIds, setClickedIds] = useState(new Set());
+ const [clickedIds, setClickedIds] = useState(new Set());
const handleUploadSuccess = (result: CloudinaryUploadResult) => {
console.log('Upload successful:', result);
@@ -26,8 +37,7 @@ function App() {
alert(`Upload failed: ${error.message}`);
};
- const copyPrompt = (e: React.MouseEvent, id: number) => {
- const text = e.currentTarget.textContent ?? '';
+ const copyPrompt = (text: string, id: number) => {
void navigator.clipboard.writeText(text).then(() => {
setClickedIds((prev) => new Set(prev).add(id));
setTimeout(() => setClickedIds( (prev) => {
@@ -83,20 +93,16 @@ function App() {
Copy and paste one of these prompts into your AI assistant:
- {hasUploadPreset ? (
- <>
- - copyPrompt(e, 0)} title="Click to copy" className={ clickedIds.has(0) ? "clicked" : '' }>Create an image gallery with lazy loading and responsive images
- - copyPrompt(e, 1)} title="Click to copy" className={ clickedIds.has(1) ? "clicked" : '' }>Create a video player that plays a Cloudinary video
- - copyPrompt(e, 2)} title="Click to copy" className={ clickedIds.has(2) ? "clicked" : '' }>Add image overlays with text or logos
- >
- ) : (
- <>
- - copyPrompt(e, 0)} title="Click to copy" className={ clickedIds.has(0) ? "clicked" : '' }>Let's try uploading — help me add an upload preset and upload widget
- - copyPrompt(e, 1)} title="Click to copy" className={ clickedIds.has(1) ? "clicked" : '' }>Create an image gallery with lazy loading and responsive images
- - copyPrompt(e, 2)} title="Click to copy" className={ clickedIds.has(2) ? "clicked" : '' }>Create a video player that plays a Cloudinary video
- - copyPrompt(e, 3)} title="Click to copy" className={ clickedIds.has(3) ? "clicked" : '' }>Add image overlays with text or logos
- >
- )}
+ {(hasUploadPreset ? PROMPTS_WITH_UPLOAD : PROMPTS_WITHOUT_UPLOAD).map((text, i) => (
+ - copyPrompt(text, i)}
+ title="Click to copy"
+ className={clickedIds.has(i) ? 'clicked' : ''}
+ >
+ {text}
+
+ ))}
From 82b2ae0537d6bf5f83b9ef9a8544bb9d9137d4cf Mon Sep 17 00:00:00 2001
From: semantic-release-bot
Date: Thu, 12 Feb 2026 05:16:00 +0000
Subject: [PATCH 11/20] chore(release): 1.0.0-beta.17 [skip ci]
# [1.0.0-beta.17](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.16...v1.0.0-beta.17) (2026-02-12)
### Bug Fixes
* simplified questions into arrays ([bade600](https://github.com/cloudinary-devs/create-cloudinary-react/commit/bade600ee63de7a7c3d8eec40569f8896f96a7bd))
### Features
* prompt copied animation ([9ad35b2](https://github.com/cloudinary-devs/create-cloudinary-react/commit/9ad35b2351a69bca6d4dcd716b10a1508d5228a8))
---
CHANGELOG.md | 12 ++++++++++++
package.json | 2 +-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 77dfb28..22f023e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,15 @@
+# [1.0.0-beta.17](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.16...v1.0.0-beta.17) (2026-02-12)
+
+
+### Bug Fixes
+
+* simplified questions into arrays ([bade600](https://github.com/cloudinary-devs/create-cloudinary-react/commit/bade600ee63de7a7c3d8eec40569f8896f96a7bd))
+
+
+### Features
+
+* prompt copied animation ([9ad35b2](https://github.com/cloudinary-devs/create-cloudinary-react/commit/9ad35b2351a69bca6d4dcd716b10a1508d5228a8))
+
# [1.0.0-beta.16](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.15...v1.0.0-beta.16) (2026-02-11)
diff --git a/package.json b/package.json
index 076aef4..6b9b975 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.16",
+ "version": "1.0.0-beta.17",
"description": "Scaffold a Cloudinary React + Vite + TypeScript project with interactive setup",
"type": "module",
"bin": {
From 9db39ee8fc149c748ea422544a79b45a60365f47 Mon Sep 17 00:00:00 2001
From: strausr
Date: Fri, 13 Feb 2026 16:01:36 -0800
Subject: [PATCH 12/20] fix: update video player example
---
templates/.cursorrules.template | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/templates/.cursorrules.template b/templates/.cursorrules.template
index 0ae4eb3..c95f311 100644
--- a/templates/.cursorrules.template
+++ b/templates/.cursorrules.template
@@ -420,7 +420,8 @@ Use when the user asks for a **video player** (styled UI, controls, playlists).
**Rule: imperative element only.** Do **not** pass a React-managed `` to the player — the library mutates the DOM and React will throw removeChild errors. Create the video element with `document.createElement('video')`, append it to a container ref, and pass that element to `videoPlayer(el, ...)`.
- **Package**: `cloudinary-video-player`. Install with `npm install cloudinary-video-player` (no version).
-- **Import**: `import { videoPlayer } from 'cloudinary-video-player'` (named) and `import 'cloudinary-video-player/cld-video-player.min.css'` (no `dist/` in path).
+- **Import**: `import { videoPlayer } from 'cloudinary-video-player'` (named) and `import 'cloudinary-video-player/cld-video-player.min.css'` (no `dist/` in path). The package only exposes paths under `lib/` via `exports`; use `cld-video-player.min.css` (no `dist/`), which resolves to `lib/cld-video-player.min.css`.
+- ❌ **WRONG**: `import 'cloudinary-video-player/dist/cld-video-player.min.css'` — package `exports` do not expose `dist/`; the valid path is `cloudinary-video-player/cld-video-player.min.css`.
- **player.source()** takes an **object**: `player.source({ publicId: 'samples/elephants' })`. Not a string.
- **Cleanup**: Call `player.dispose()`, then **only if** `el.parentNode` exists call `el.parentNode.removeChild(el)` (avoids NotFoundError).
- **If init fails** (CSP, extensions, timing): render **AdvancedVideo** with the same publicId. Do not relax CSP in index.html or ask the user to disable extensions.
From 2a69d7ada9de1cb2751bbd4c1d344422b4c2dd5e Mon Sep 17 00:00:00 2001
From: strausr
Date: Wed, 18 Feb 2026 09:45:57 -0800
Subject: [PATCH 13/20] fix: update registration link
---
README.md | 2 +-
cli.js | 4 ++--
templates/README.md.template | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 2fc267a..6e3b4cb 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ Scaffold a Cloudinary React + Vite + TypeScript project with interactive setup.
- Node.js 18+ installed
- A Cloudinary account (free tier available)
- - [Sign up for free](https://cloudinary.com/users/register/free)
+ - [Sign up for free](https://cld.media/reactregister)
- Your cloud name is in your [dashboard](https://console.cloudinary.com/app/home/dashboard)
## Usage
diff --git a/cli.js b/cli.js
index 4d7243b..a27f07c 100755
--- a/cli.js
+++ b/cli.js
@@ -70,7 +70,7 @@ async function main() {
} else {
console.log(chalk.cyan.bold('\n🚀 Cloudinary React + Vite\n'));
- console.log(chalk.gray('💡 Need a Cloudinary account? Sign up for free: https://cloudinary.com/users/register/free\n'));
+ console.log(chalk.gray('💡 Need a Cloudinary account? Sign up for free: https://cld.media/reactregister\n'));
const questions = [
{
@@ -101,7 +101,7 @@ async function main() {
if (!input.trim()) {
return chalk.yellow(
'Cloud name is required.\n' +
- ' → Sign up: https://cloudinary.com/users/register/free\n' +
+ ' → Sign up: https://cld.media/reactregister\n' +
' → Find your cloud name: https://console.cloudinary.com/app/home/dashboard'
);
}
diff --git a/templates/README.md.template b/templates/README.md.template
index 3cec979..fa24eac 100644
--- a/templates/README.md.template
+++ b/templates/README.md.template
@@ -11,7 +11,7 @@ npm run dev
## Cloudinary Setup
This project uses Cloudinary for image management. If you don't have a Cloudinary account yet:
-- [Sign up for free](https://cloudinary.com/users/register/free)
+- [Sign up for free](https://cld.media/reactregister)
- Find your cloud name in your [dashboard](https://console.cloudinary.com/app/home/dashboard)
## Environment Variables
From 1ca04cfbd181c4fd952931d228b25926db1c9198 Mon Sep 17 00:00:00 2001
From: semantic-release-bot
Date: Wed, 18 Feb 2026 17:47:10 +0000
Subject: [PATCH 14/20] chore(release): 1.0.0-beta.18 [skip ci]
# [1.0.0-beta.18](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.17...v1.0.0-beta.18) (2026-02-18)
### Bug Fixes
* update registration link ([2a69d7a](https://github.com/cloudinary-devs/create-cloudinary-react/commit/2a69d7ada9de1cb2751bbd4c1d344422b4c2dd5e))
* update video player example ([9db39ee](https://github.com/cloudinary-devs/create-cloudinary-react/commit/9db39ee8fc149c748ea422544a79b45a60365f47))
---
CHANGELOG.md | 8 ++++++++
package.json | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 22f023e..5151474 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+# [1.0.0-beta.18](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.17...v1.0.0-beta.18) (2026-02-18)
+
+
+### Bug Fixes
+
+* update registration link ([2a69d7a](https://github.com/cloudinary-devs/create-cloudinary-react/commit/2a69d7ada9de1cb2751bbd4c1d344422b4c2dd5e))
+* update video player example ([9db39ee](https://github.com/cloudinary-devs/create-cloudinary-react/commit/9db39ee8fc149c748ea422544a79b45a60365f47))
+
# [1.0.0-beta.17](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.16...v1.0.0-beta.17) (2026-02-12)
diff --git a/package.json b/package.json
index 6b9b975..8ef599a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.17",
+ "version": "1.0.0-beta.18",
"description": "Scaffold a Cloudinary React + Vite + TypeScript project with interactive setup",
"type": "module",
"bin": {
From b7a77caaf4bf052c68bd912a0ae9c51d424d07cd Mon Sep 17 00:00:00 2001
From: strausr
Date: Wed, 18 Feb 2026 14:55:55 -0800
Subject: [PATCH 15/20] fix: update readme
---
README.md | 4 ++--
cli.js | 26 ++++++++++++++------------
2 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/README.md b/README.md
index 6e3b4cb..7acffad 100644
--- a/README.md
+++ b/README.md
@@ -44,10 +44,10 @@ During setup, you'll be asked which AI coding assistant(s) you're using. The CLI
- ✅ **Cursor** → `.cursorrules` + `.cursor/mcp.json` (if selected)
- ✅ **GitHub Copilot** → `.github/copilot-instructions.md`
-- ✅ **Claude Code (VS Code extension)** → `.claude`, `claude.md` + `.cursor/mcp.json` (if selected)
+- ✅ **Claude Code** → `CLAUDE.md` + `.mcp.json` (if selected)
- ✅ **Generic AI tools** → `AI_INSTRUCTIONS.md`, `PROMPT.md`
-**MCP Configuration**: The `.cursor/mcp.json` file is automatically generated if you select Cursor or Claude, as it works with both tools.
+**MCP Configuration**: Cursor and Claude Code use different config paths. If you select **Cursor**, the CLI writes `.cursor/mcp.json`. If you select **Claude**, it writes `.mcp.json` in the project root. Each tool only reads its own path, so both files are generated when you select both.
These rules help AI assistants understand Cloudinary React SDK patterns, common errors, and best practices. The generated app also includes an "AI Prompts" section with ready-to-use suggestions for your AI assistant.
diff --git a/cli.js b/cli.js
index a27f07c..91edae0 100755
--- a/cli.js
+++ b/cli.js
@@ -141,7 +141,7 @@ async function main() {
choices: [
{ name: 'Cursor', value: 'cursor' },
{ name: 'GitHub Copilot', value: 'copilot' },
- { name: 'Claude Code (VS Code extension)', value: 'claude' },
+ { name: 'Claude Code', value: 'claude' },
{ name: 'Other / Generic AI tools', value: 'generic' },
],
default: ['cursor'],
@@ -262,18 +262,21 @@ async function main() {
writeFileSync(join(projectPath, 'PROMPT.md'), aiRulesContent);
}
- // Generate MCP configuration if using Cursor or Claude (MCP works with both)
- if (aiTools.includes('cursor') || aiTools.includes('claude')) {
- const mcpTemplatePath = join(TEMPLATES_DIR, '.cursor/mcp.json.template');
- if (existsSync(mcpTemplatePath)) {
+ // Generate MCP configuration: Cursor uses .cursor/mcp.json, Claude Code uses .mcp.json in project root
+ const mcpTemplatePath = join(TEMPLATES_DIR, '.cursor/mcp.json.template');
+ if (existsSync(mcpTemplatePath)) {
+ const mcpContent = replaceTemplate(
+ readFileSync(mcpTemplatePath, 'utf-8'),
+ templateVars
+ );
+ if (aiTools.includes('cursor')) {
const cursorDir = join(projectPath, '.cursor');
mkdirSync(cursorDir, { recursive: true });
- const mcpContent = replaceTemplate(
- readFileSync(mcpTemplatePath, 'utf-8'),
- templateVars
- );
writeFileSync(join(cursorDir, 'mcp.json'), mcpContent);
}
+ if (aiTools.includes('claude')) {
+ writeFileSync(join(projectPath, '.mcp.json'), mcpContent);
+ }
}
}
@@ -291,9 +294,8 @@ async function main() {
if (aiTools.includes('copilot')) console.log(chalk.gray(' • GitHub Copilot: .github/copilot-instructions.md'));
if (aiTools.includes('claude')) console.log(chalk.gray(' • Claude: CLAUDE.md'));
if (aiTools.includes('generic')) console.log(chalk.gray(' • Generic: AI_INSTRUCTIONS.md, PROMPT.md'));
- if (aiTools.includes('cursor') || aiTools.includes('claude')) {
- console.log(chalk.gray(' • MCP (Cursor/Claude): .cursor/mcp.json'));
- }
+ if (aiTools.includes('cursor')) console.log(chalk.gray(' • MCP (Cursor): .cursor/mcp.json'));
+ if (aiTools.includes('claude')) console.log(chalk.gray(' • MCP (Claude Code): .mcp.json'));
console.log('');
}
From 49621316c9f21a7ab0d77640e5a98dbbe20dce27 Mon Sep 17 00:00:00 2001
From: semantic-release-bot
Date: Wed, 18 Feb 2026 23:00:20 +0000
Subject: [PATCH 16/20] chore(release): 1.0.0-beta.19 [skip ci]
# [1.0.0-beta.19](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.18...v1.0.0-beta.19) (2026-02-18)
### Bug Fixes
* update readme ([b7a77ca](https://github.com/cloudinary-devs/create-cloudinary-react/commit/b7a77caaf4bf052c68bd912a0ae9c51d424d07cd))
---
CHANGELOG.md | 7 +++++++
package.json | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5151474..447ab92 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# [1.0.0-beta.19](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.18...v1.0.0-beta.19) (2026-02-18)
+
+
+### Bug Fixes
+
+* update readme ([b7a77ca](https://github.com/cloudinary-devs/create-cloudinary-react/commit/b7a77caaf4bf052c68bd912a0ae9c51d424d07cd))
+
# [1.0.0-beta.18](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.17...v1.0.0-beta.18) (2026-02-18)
diff --git a/package.json b/package.json
index 8ef599a..0658ac7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.18",
+ "version": "1.0.0-beta.19",
"description": "Scaffold a Cloudinary React + Vite + TypeScript project with interactive setup",
"type": "module",
"bin": {
From 462378aad5b3b4b7679adb572dc469f405c02763 Mon Sep 17 00:00:00 2001
From: Jen Looper
Date: Wed, 18 Feb 2026 15:23:17 -0800
Subject: [PATCH 17/20] Update README.md
---
README.md | 107 ++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 76 insertions(+), 31 deletions(-)
diff --git a/README.md b/README.md
index 7acffad..dcea541 100644
--- a/README.md
+++ b/README.md
@@ -1,57 +1,99 @@
# create-cloudinary-react
-> **Beta Release** - This is a beta version. We welcome feedback and bug reports!
-
-Part of the [Cloudinary Developers](https://github.com/cloudinary-devs) organization.
+[](https://www.npmjs.com/package/create-cloudinary-react)
+[](https://opensource.org/licenses/MIT)
+[](http://makeapullrequest.com)
-Scaffold a Cloudinary React + Vite + TypeScript project with interactive setup.
+**The fastest way to start building with Cloudinary and React.**
-## Prerequisites
+Scaffold a modern, production-ready Cloudinary application with React 19, Vite 6, and TypeScript 5. Features interactive setup, automatic environment configuration, and built-in AI coding assistance.
- Node.js 18+ installed
- A Cloudinary account (free tier available)
- [Sign up for free](https://cld.media/reactregister)
- Your cloud name is in your [dashboard](https://console.cloudinary.com/app/home/dashboard)
-## Usage
+> **Beta Release** - This is a beta version. We welcome feedback and bug reports!
+
+Part of the [Cloudinary Developers](https://github.com/cloudinary-devs) organization.
+
+
+
+## 📽️ Demo
+
+[](https://res.cloudinary.com/drir0kpia/video/upload/v1771449633/reactstarterdemo.mp4)
+
+
+## 🎬 Features
+
+- **🚀 Modern Stack**: React 19 + Vite 6 + TypeScript 5.7
+- **📦 Cloudinary SDKs**: Pre-configured `@cloudinary/react`
+- **🤖 AI-First**: Auto-generates configuration for Cursor, GitHub Copilot, and Claude
+- **🛠️ Best Practices**: ESLint 9 + TypeScript-ESLint, strict type checking
+- **⚡ Interactive Setup**: Validates your cloud name and configures `.env` automatically
+- **🎨 Typed Components**: Includes a fully typed Upload Widget component
+- **🔌 MCP Support**: Built-in Model Context Protocol configuration for advanced AI integrations
+
+## 🚀 Quick Start
+
+Ensure you have Node.js 18+ installed.
```bash
npx create-cloudinary-react
```
+*(No installation required)*
+
+The CLI will guide you through:
+1. **Project Name**: naming your new folder
+2. **Cloud Name**: entering your [Cloudinary cloud name](https://console.cloudinary.com/app/home/dashboard)
+3. **Upload Preset** (Optional): handling unsigned uploads
+4. **AI Assistant**: generating custom rules for your tool of choice (Cursor, VS Code, etc.)
+
+## 🛠️ What's Included
-The CLI will prompt you for:
-- Project name
-- **Cloudinary cloud name** (found in your [dashboard](https://console.cloudinary.com/app/home/dashboard))
-- Unsigned upload preset (optional - required for uploads, but transformations work without it)
-- AI coding assistant(s) you're using (Cursor, GitHub Copilot, Claude, etc.)
-- Whether to install dependencies
-- Whether to start dev server
+Your new project comes with:
-## Features
+- **`src/`**: specialized for Cloudinary workflows
+- **`src/components/UploadWidget.tsx`**: A ready-to-use, typed upload component
+- **`.env`**: Pre-filled with your Cloud Name (and Upload Preset if provided)
+- **`README.md`**: Custom instructions for your specific project
+- **AI Configuration**:
+ - `.cursorrules` / `.cursor/mcp.json` (for Cursor)
+ - `.github/copilot-instructions.md` (for Copilot)
+ - `.claude` / `claude.md` (for Claude)
-- ✅ Interactive setup with validation
-- ✅ Pre-configured Cloudinary React SDK
-- ✅ TypeScript + Vite + React 19
-- ✅ Typed Upload Widget component
-- ✅ Environment variables with VITE_ prefix
-- ✅ Multi-tool AI assistant support (Cursor, GitHub Copilot, Claude, and more)
-- ✅ MCP configuration for Cloudinary integration
-- ✅ ESLint + TypeScript configured
+## 🤖 AI Assistant Support
-## AI Assistant Support
+We believe AI is the future of development. This starter kit doesn't just give you code; it gives your AI context.
-During setup, you'll be asked which AI coding assistant(s) you're using. The CLI will generate the appropriate configuration files:
+During setup, select your AI tool to generate **Context Rules**. These rules teach your AI:
+- How to construct Cloudinary transformation URLs correctly
+- How to use the `@cloudinary/react` SDK components
+- Common pitfalls to avoid (like mixing up import paths)
+- How to handle upload widget events
-- ✅ **Cursor** → `.cursorrules` + `.cursor/mcp.json` (if selected)
-- ✅ **GitHub Copilot** → `.github/copilot-instructions.md`
-- ✅ **Claude Code** → `CLAUDE.md` + `.mcp.json` (if selected)
-- ✅ **Generic AI tools** → `AI_INSTRUCTIONS.md`, `PROMPT.md`
+**Supported Tools:**
+- ✅ **Cursor** (Rules + MCP)
+- ✅ **GitHub Copilot** (Instructions)
+- ✅ **Claude** (Project context + MCP)
+- ✅ **Generic LLMs** (System prompts provided)
-**MCP Configuration**: Cursor and Claude Code use different config paths. If you select **Cursor**, the CLI writes `.cursor/mcp.json`. If you select **Claude**, it writes `.mcp.json` in the project root. Each tool only reads its own path, so both files are generated when you select both.
+## 📋 Prerequisites
-These rules help AI assistants understand Cloudinary React SDK patterns, common errors, and best practices. The generated app also includes an "AI Prompts" section with ready-to-use suggestions for your AI assistant.
+- **Node.js 18+**
+- **Cloudinary Account**: [Sign up for free](https://cloudinary.com/users/register/free) if you haven't already.
-## Development
+## 🤝 Contributing
+
+Contributions are welcome! Please feel free to submit a Pull Request.
+
+1. Fork the repository
+2. Create your feature branch (`git checkout -b feature/amazing-feature`)
+3. Commit your changes (`git commit -m 'feat: add some amazing feature'`)
+4. Push to the branch (`git push origin feature/amazing-feature`)
+5. Open a Pull Request
+
+## ⚙️ Development
This project uses [Conventional Commits](https://www.conventionalcommits.org/) for version management and [semantic-release](https://github.com/semantic-release/semantic-release) for automated releases.
@@ -79,3 +121,6 @@ Releases are triggered manually via GitHub Actions workflow. The workflow uses n
- `perf`: Performance improvements
- `chore`: Other changes
+## 📄 License
+
+This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
From efd03e5119ee50edf21e92e3008d87389b227683 Mon Sep 17 00:00:00 2001
From: semantic-release-bot
Date: Mon, 23 Feb 2026 22:14:57 +0000
Subject: [PATCH 18/20] chore(release): 1.0.0-beta.20 [skip ci]
# [1.0.0-beta.20](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.19...v1.0.0-beta.20) (2026-02-23)
### Bug Fixes
* Merge pull request [#9](https://github.com/cloudinary-devs/create-cloudinary-react/issues/9) from jlooper-cloudinary/main ([9696686](https://github.com/cloudinary-devs/create-cloudinary-react/commit/96966864d65168b0210a8200f26c9d0d144b6fa9))
---
CHANGELOG.md | 7 +++++++
package.json | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 447ab92..7de15b1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# [1.0.0-beta.20](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.19...v1.0.0-beta.20) (2026-02-23)
+
+
+### Bug Fixes
+
+* Merge pull request [#9](https://github.com/cloudinary-devs/create-cloudinary-react/issues/9) from jlooper-cloudinary/main ([9696686](https://github.com/cloudinary-devs/create-cloudinary-react/commit/96966864d65168b0210a8200f26c9d0d144b6fa9))
+
# [1.0.0-beta.19](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.18...v1.0.0-beta.19) (2026-02-18)
diff --git a/package.json b/package.json
index 0658ac7..aab8c17 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.19",
+ "version": "1.0.0-beta.20",
"description": "Scaffold a Cloudinary React + Vite + TypeScript project with interactive setup",
"type": "module",
"bin": {
From 54f633e6fc2a6e800979c9962383c8f83523f79b Mon Sep 17 00:00:00 2001
From: strausr
Date: Wed, 25 Feb 2026 09:17:45 -0800
Subject: [PATCH 19/20] fix: update title in readme and ui
---
cli.js | 2 +-
templates/src/App.tsx.template | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/cli.js b/cli.js
index 91edae0..01a6c15 100755
--- a/cli.js
+++ b/cli.js
@@ -69,7 +69,7 @@ async function main() {
} else {
- console.log(chalk.cyan.bold('\n🚀 Cloudinary React + Vite\n'));
+ console.log(chalk.cyan.bold('\n🚀 Cloudinary React Starter Kit\n'));
console.log(chalk.gray('💡 Need a Cloudinary account? Sign up for free: https://cld.media/reactregister\n'));
const questions = [
diff --git a/templates/src/App.tsx.template b/templates/src/App.tsx.template
index 7fe7adc..01bacf8 100644
--- a/templates/src/App.tsx.template
+++ b/templates/src/App.tsx.template
@@ -60,7 +60,7 @@ function App() {
return (
- Cloudinary React + Vite
+ Cloudinary React Starter Kit
This is a ready-to-use development environment with Cloudinary integration.
{hasUploadPreset && (
From b07017ec6c9e9a30e6fa9768766f6edd1300bde7 Mon Sep 17 00:00:00 2001
From: semantic-release-bot
Date: Wed, 25 Feb 2026 17:20:00 +0000
Subject: [PATCH 20/20] chore(release): 1.0.0-beta.21 [skip ci]
# [1.0.0-beta.21](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.20...v1.0.0-beta.21) (2026-02-25)
### Bug Fixes
* update title in readme and ui ([54f633e](https://github.com/cloudinary-devs/create-cloudinary-react/commit/54f633e6fc2a6e800979c9962383c8f83523f79b))
---
CHANGELOG.md | 7 +++++++
package.json | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7de15b1..0a27e20 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# [1.0.0-beta.21](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.20...v1.0.0-beta.21) (2026-02-25)
+
+
+### Bug Fixes
+
+* update title in readme and ui ([54f633e](https://github.com/cloudinary-devs/create-cloudinary-react/commit/54f633e6fc2a6e800979c9962383c8f83523f79b))
+
# [1.0.0-beta.20](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.19...v1.0.0-beta.20) (2026-02-23)
diff --git a/package.json b/package.json
index aab8c17..6718323 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "create-cloudinary-react",
- "version": "1.0.0-beta.20",
+ "version": "1.0.0-beta.21",
"description": "Scaffold a Cloudinary React + Vite + TypeScript project with interactive setup",
"type": "module",
"bin": {