{"_id":"@aigentic/cnn","_rev":"2-938935b80fe394ff336f5b4d2cbe2461","name":"@aigentic/cnn","dist-tags":{"alpha":"0.1.0","latest":"0.1.0"},"versions":{"0.1.0":{"name":"@aigentic/cnn","version":"0.1.0","keywords":["cnn","embeddings","image","wasm","simd","machine-learning","contrastive-learning","mobilenet","ruvector"],"author":{"name":"ruvnet"},"license":"MIT","_id":"@aigentic/cnn@0.1.0","maintainers":[{"name":"aigentic","email":"engineering@aigentic.net"}],"homepage":"https://github.com/ruvnet/ruvector#readme","bugs":{"url":"https://github.com/ruvnet/ruvector/issues"},"dist":{"shasum":"eb0a809761202ae3739fb637178be45de5e577c6","tarball":"https://registry.npmjs.org/@aigentic/cnn/-/cnn-0.1.0.tgz","fileCount":8,"integrity":"sha512-G4F/HKYHBkcBKcs0uYdTekiMhQQdPZOgfNTVfX7f0yqB2V652y5YWke9UUD+oWRctWoF2KPO8PxYtUGLmpoqxQ==","signatures":[{"sig":"MEYCIQC8y5wBXXbjLOAdQuCOjsNqH7x6s3sG2MFLI1NOywrCjwIhAKFu6pDkL47IriK0UPxZ16oFEMmj343VCKYp3/XZLK2f","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":109879},"main":"index.js","types":"index.d.ts","module":"index.mjs","engines":{"node":">=16.0.0"},"gitHead":"e2cb6210ce8d478b39cad81872a4aef78a05ceb4","scripts":{"test":"node test.js","build":"wasm-pack build ../../crates/ruvector-cnn-wasm --target web --out-dir ../../npm/packages/ruvector-cnn/pkg","postbuild":"cp pkg/* . && rm -rf pkg"},"_npmUser":{"name":"aigentic","email":"engineering@aigentic.net"},"repository":{"url":"git+https://github.com/ruvnet/ruvector.git","type":"git","directory":"npm/packages/ruvector-cnn"},"_npmVersion":"11.12.0","description":"CNN feature extraction for image embeddings - SIMD-optimized, pure Rust/WASM","directories":{},"_nodeVersion":"22.22.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/cnn_0.1.0_1779324071614_0.7351272765693702","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-05-21T00:41:11.437Z","modified":"2026-09-13T15:30:29.149Z","0.1.0":"2026-05-21T00:41:11.765Z"},"bugs":{"url":"https://github.com/ruvnet/ruvector/issues"},"author":{"name":"ruvnet"},"license":"MIT","homepage":"https://github.com/ruvnet/ruvector#readme","keywords":["cnn","embeddings","image","wasm","simd","machine-learning","contrastive-learning","mobilenet","ruvector"],"repository":{"url":"git+https://github.com/ruvnet/ruvector.git","type":"git","directory":"npm/packages/ruvector-cnn"},"description":"CNN feature extraction for image embeddings - SIMD-optimized, pure Rust/WASM","maintainers":[{"email":"engineering@aigentic.net","name":"aiggy"}],"readme":"# @aigentic/cnn\n\n[![npm version](https://img.shields.io/npm/v/@aigentic/cnn.svg)](https://www.npmjs.com/package/@aigentic/cnn)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n**Turn images into searchable vectors** — runs in browsers, no backend needed.\n\n## What Does This Do?\n\nThis package converts images into numbers (called \"embeddings\") that describe what's in the picture. Similar images produce similar numbers.\n\n**Use it to:**\n- Build \"find similar images\" features\n- Group photos by what they show\n- Create visual search for products\n- Compare images without AI APIs\n\n```javascript\nimport { init, CnnEmbedder } from '@aigentic/cnn';\n\nawait init();\nconst embedder = new CnnEmbedder();\n\n// Turn an image into numbers\nconst numbers = embedder.extract(imagePixels, 224, 224);\n\n// Compare two images (1.0 = identical, 0 = unrelated)\nconst similarity = embedder.cosineSimilarity(numbers1, numbers2);\n```\n\n## Why Use This?\n\n| What You Get | Why It Matters |\n|--------------|----------------|\n| Runs in the browser | No server costs, instant results |\n| ~5ms per image | Fast enough for real-time |\n| ~900KB download | Small enough for any website |\n| No API calls | Works offline, no per-image fees |\n| Training included | Teach it your own categories |\n\n## Installation\n\n```bash\nnpm install @aigentic/cnn\n```\n\n## How to Use It\n\n### 1. Extract Image Features\n\n```javascript\nimport { init, CnnEmbedder } from '@aigentic/cnn';\n\n// Start the engine (do this once)\nawait init();\n\n// Create the feature extractor\nconst embedder = new CnnEmbedder({\n  embeddingDim: 512,  // How many numbers per image\n  normalize: true      // Make comparisons easier\n});\n\n// Get pixels from an image (RGB, no transparency)\n// Each pixel has 3 values: red, green, blue (0-255)\nconst pixels = new Uint8Array(224 * 224 * 3);\n\n// Turn pixels into 512 numbers that describe the image\nconst features = embedder.extract(pixels, 224, 224);\nconsole.log('Got', features.length, 'numbers'); // 512\n```\n\n### 2. Compare Two Images\n\n```javascript\nconst features1 = embedder.extract(image1Pixels, 224, 224);\nconst features2 = embedder.extract(image2Pixels, 224, 224);\n\n// How similar are they? (1.0 = same, 0 = different, -1 = opposite)\nconst score = embedder.cosineSimilarity(features1, features2);\n\nif (score > 0.8) {\n  console.log('These images are very similar!');\n} else if (score > 0.5) {\n  console.log('These images have some things in common');\n} else {\n  console.log('These images are different');\n}\n```\n\n### 3. Find the Most Similar Image\n\n```javascript\n// Your collection of images (already converted to features)\nconst catalog = [\n  { name: 'red-shoe.jpg', features: embedder.extract(redShoePixels, 224, 224) },\n  { name: 'blue-bag.jpg', features: embedder.extract(blueBagPixels, 224, 224) },\n  { name: 'red-dress.jpg', features: embedder.extract(redDressPixels, 224, 224) },\n];\n\n// User uploads a photo\nconst userPhoto = embedder.extract(uploadedPixels, 224, 224);\n\n// Find the best match\nlet bestMatch = null;\nlet bestScore = -1;\n\nfor (const item of catalog) {\n  const score = embedder.cosineSimilarity(userPhoto, item.features);\n  if (score > bestScore) {\n    bestScore = score;\n    bestMatch = item.name;\n  }\n}\n\nconsole.log('Best match:', bestMatch, 'Score:', bestScore);\n```\n\n### 4. Get Pixels from a Canvas\n\n```javascript\n// If you have an image in a canvas element\nconst canvas = document.getElementById('myCanvas');\nconst ctx = canvas.getContext('2d');\n\n// Get the pixel data\nconst imageData = ctx.getImageData(0, 0, 224, 224);\n\n// Canvas gives RGBA (4 values per pixel), we need RGB (3 values)\nconst rgb = new Uint8Array(224 * 224 * 3);\nfor (let i = 0, j = 0; i < imageData.data.length; i += 4, j += 3) {\n  rgb[j] = imageData.data[i];       // Red\n  rgb[j + 1] = imageData.data[i + 1]; // Green\n  rgb[j + 2] = imageData.data[i + 2]; // Blue\n  // Skip alpha (imageData.data[i + 3])\n}\n\nconst features = embedder.extract(rgb, 224, 224);\n```\n\n## Training (Teaching It Your Categories)\n\nYou can train the model to be better at recognizing your specific images.\n\n### Contrastive Training (SimCLR style)\n\nShow it pairs of images that should match:\n\n```javascript\nimport { init, InfoNCELoss, CnnEmbedder } from '@aigentic/cnn';\n\nawait init();\n\nconst embedder = new CnnEmbedder();\nconst trainer = new InfoNCELoss(0.1); // Lower = stricter matching\n\n// Get features for your training pairs\n// Pairs: image1 and image1_different_angle should match\nconst image1 = embedder.extract(photo1, 224, 224);\nconst image1_alt = embedder.extract(photo1_rotated, 224, 224);\n\n// Pack into one array: [view1s..., view2s...]\nconst batch = new Float32Array(2 * 512);\nbatch.set(image1, 0);\nbatch.set(image1_alt, 512);\n\nconst loss = trainer.forward(batch, 1, 512);\nconsole.log('Loss:', loss); // Lower is better\n```\n\n### Triplet Training\n\nShow it: \"A is similar to B, but different from C\"\n\n```javascript\nimport { init, TripletLoss, CnnEmbedder } from '@aigentic/cnn';\n\nawait init();\n\nconst embedder = new CnnEmbedder();\nconst trainer = new TripletLoss(1.0); // margin\n\n// Anchor: the reference image\n// Positive: should be similar to anchor\n// Negative: should be different from anchor\nconst anchor = embedder.extract(redShoePhoto, 224, 224);\nconst positive = embedder.extract(redShoePhoto2, 224, 224); // Same shoe\nconst negative = embedder.extract(blueBagPhoto, 224, 224);   // Different item\n\nconst loss = trainer.forward(\n  new Float32Array(anchor),\n  new Float32Array(positive),\n  new Float32Array(negative),\n  512\n);\nconsole.log('Loss:', loss);\n```\n\n## Fast Math Operations\n\nIf you're building custom features, these are optimized:\n\n```javascript\nimport { init, SimdOps, LayerOps } from '@aigentic/cnn';\n\nawait init();\n\n// Dot product (sum of element-wise multiplication)\nconst a = new Float32Array([1, 2, 3, 4]);\nconst b = new Float32Array([5, 6, 7, 8]);\nconst result = SimdOps.dotProduct(a, b); // 70\n\n// ReLU: set negative values to 0\nconst data = new Float32Array([-1, 0, 1, 7]);\nSimdOps.relu(data); // [0, 0, 1, 7]\n\n// ReLU6: clamp between 0 and 6\nSimdOps.relu6(data); // [0, 0, 1, 6]\n\n// L2 normalize (make length = 1)\nSimdOps.l2Normalize(data);\n```\n\n## Performance\n\n| What | How Long | Notes |\n|------|----------|-------|\n| Extract features (224×224 image) | ~5ms | With SIMD |\n| Compare two images | ~0.01ms | Just math |\n| Training step | ~1ms | Per batch |\n| First load | ~100ms | Downloads WASM |\n\n## Browser Support\n\nWorks in all modern browsers with WebAssembly:\n- Chrome 57+\n- Firefox 52+\n- Safari 11+\n- Edge 16+\n\nFor best speed, use browsers with SIMD128 support:\n- Chrome 91+\n- Firefox 89+\n- Safari 16.4+\n\n## Troubleshooting\n\n**\"init() takes too long\"**\n- Normal: First call downloads ~900KB WASM file\n- Fix: Call init() early, before user needs results\n\n**\"Images look wrong\"**\n- Check: Images must be 224×224 pixels\n- Check: Pixel format is RGB (3 values per pixel, not RGBA)\n- Check: Values are 0-255, not 0-1\n\n**\"Similarity scores are all low\"**\n- Try: Set `normalize: true` in CnnEmbedder options\n- Check: Are your images actually similar?\n\n## API Reference\n\n### CnnEmbedder\n\n```typescript\nnew CnnEmbedder(options?: {\n  embeddingDim?: number;  // Default: 512\n  normalize?: boolean;    // Default: true\n})\n\n.extract(pixels: Uint8Array, width: number, height: number): Float32Array\n.cosineSimilarity(a: Float32Array, b: Float32Array): number\n.embeddingDim: number\n```\n\n### InfoNCELoss\n\n```typescript\nnew InfoNCELoss(temperature?: number)  // Default: 0.1\n\n.forward(embeddings: Float32Array, batchSize: number, dim: number): number\n.temperature: number\n```\n\n### TripletLoss\n\n```typescript\nnew TripletLoss(margin?: number)  // Default: 1.0\n\n.forward(anchors, positives, negatives: Float32Array, dim: number): number\n.margin: number\n```\n\n## Related Packages\n\n- [`ruvector`](https://www.npmjs.com/package/ruvector) — Core vector database\n- [`@aigentic/attention`](https://www.npmjs.com/package/@aigentic/attention) — AI attention layers\n- [`@aigentic/gnn`](https://www.npmjs.com/package/@aigentic/gnn) — Graph neural networks\n\n## License\n\nMIT OR Apache-2.0\n","readmeFilename":"README.md"}