@harpiaresearch/vref 0.0.0-stage → 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2024, Harpia AI Research
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md CHANGED
@@ -1,3 +1,406 @@
1
- # Temporary Holding Version
1
+ <div align="center">
2
+
3
+ # VREF — Visual Reference Format
4
+
5
+ **A standardized format for curated visual references in AI image generation**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@harpiaresearch/vref)](https://www.npmjs.com/package/@harpiaresearch/vref)
8
+ [![License](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](LICENSE)
9
+
10
+ Harpia AI Research
11
+
12
+ </div>
13
+
14
+ ---
15
+
16
+ <div align="center">
17
+
18
+ ## The Problem
19
+
20
+ </div>
21
+
22
+ You know exactly what you want your AI to generate, but describing it in words is **nearly impossible**.
23
+
24
+ - 🤔 "How do I describe this art style?"
25
+ - 📸 "I have 20 reference images, but uploading them one by one is tedious"
26
+ - 🔄 "I can't easily share or reuse my reference collections"
27
+ - 😤 "Text prompts alone just don't capture the vision"
28
+
29
+ **Visual concepts are hard to describe, but easy to show.**
30
+
31
+ ---
32
+
33
+ <div align="center">
34
+
35
+ ## The Solution
36
+
37
+ **VREF** (Visual Reference Format) is a simple, open standard that packages your visual references into a single `.vref` file.
38
+
39
+ ```
40
+ Your 50 reference images → one references.vref file
41
+ ```
42
+
43
+ </div>
44
+
45
+ ### How It Works
46
+
47
+ ```
48
+ 1. Package images → references.vref
49
+ 2. Upload to AI platform
50
+ 3. Platform samples N random images
51
+ 4. You write text prompt
52
+ 5. AI generates with visual context
53
+ ```
54
+
55
+ Instead of fighting with text descriptions, you **show the AI what you want**.
56
+
57
+ ---
58
+
59
+ <div align="center">
60
+
61
+ ## Why You Should Use VREF
62
+
63
+ </div>
64
+
65
+ ### ✅ For Creators
66
+
67
+ **Stop struggling with prompts.**
68
+ - Package your mood boards, style references, and inspirations
69
+ - Upload once, reuse forever
70
+ - Share with your team or community
71
+
72
+ **Example:** Download `roblox-banners.vref` → Upload → Describe what you want → Get perfect results
73
+
74
+ ### ✅ For Platforms
75
+
76
+ **Better user experience.**
77
+ - Users get better results faster
78
+ - Reduces prompt engineering frustration
79
+ - Differentiates your platform
80
+ - Simple to implement (< 1 day)
81
+
82
+ ### ✅ For Everyone
83
+
84
+ **It's an open standard.**
85
+ - No vendor lock-in
86
+ - Portable across platforms
87
+ - Community-driven
88
+ - Free forever
89
+
90
+ ---
91
+
92
+ <div align="center">
93
+
94
+ ## Real-World Use Cases
95
+
96
+ </div>
97
+
98
+ ### 🎮 Game Development
99
+ ```
100
+ rpg-sprites.vref → Character references
101
+ platformer-tiles.vref → Level design inspiration
102
+ ui-elements.vref → Interface styles
103
+ ```
104
+
105
+ ### 🎨 Creative Work
106
+ ```
107
+ architecture.vref → Building styles
108
+ color-palettes.vref → Mood and tone
109
+ typography.vref → Font and layout ideas
110
+ ```
111
+
112
+ ### 🤖 AI Training
113
+ ```
114
+ training-data.vref → Curated datasets
115
+ style-transfer.vref → Style references
116
+ fine-tuning.vref → Model-specific data
117
+ ```
118
+
119
+ ---
120
+
121
+ <div align="center">
122
+
123
+ ## Installation
124
+
125
+ </div>
126
+
127
+ ```bash
128
+ npm install @harpiaresearch/vref
129
+ ```
130
+
131
+ Or use directly:
132
+
133
+ ```bash
134
+ npx @harpiaresearch/vref
135
+ ```
136
+
137
+ ---
138
+
139
+ <div align="center">
140
+
141
+ ## Quick Start
142
+
143
+ </div>
144
+
145
+ ### Creating a .vref File
146
+
147
+ **CLI:**
148
+ ```bash
149
+ # From a directory
150
+ npx @harpiaresearch/vref ./my-images -o references.vref
151
+
152
+ # With metadata
153
+ npx @harpiaresearch/vref ./images -o pack.vref \
154
+ -n "My Reference Pack" \
155
+ -d "Collection of art references" \
156
+ -t "art,style,inspiration"
157
+ ```
158
+
159
+ **Code:**
160
+ ```typescript
161
+ import { VREFWriter } from '@harpiaresearch/vref';
162
+
163
+ const writer = new VREFWriter({
164
+ fileName: 'references.vref',
165
+ description: 'Art style references',
166
+ tags: ['art', 'style'],
167
+ });
168
+
169
+ writer.addImagesFromDirectory('./images');
170
+ writer.write('references.vref');
171
+ ```
172
+
173
+ ### Reading a .vref File
174
+
175
+ ```typescript
176
+ import { VREFReader } from '@harpiaresearch/vref';
177
+
178
+ // Read file
179
+ const vref = VREFReader.read('references.vref', { loadImages: true });
180
+
181
+ console.log(`Loaded ${vref.manifest.imageCount} images`);
182
+
183
+ // Sample 3 random images
184
+ const randomSamples = vref.sample(3);
185
+
186
+ // Get specific image
187
+ const image = vref.getImage('photo1.png');
188
+ ```
189
+
190
+ ---
191
+
192
+ <div align="center">
193
+
194
+ ## For AI Platform Developers
195
+
196
+ Integrating VREF takes **< 1 day**:
197
+
198
+ </div>
199
+
200
+ ```typescript
201
+ import { VREFReader } from '@harpiaresearch/vref';
202
+
203
+ // 1. User uploads .vref
204
+ const vref = VREFReader.read(uploadedFile, { loadImages: true });
205
+
206
+ // 2. Show slider: "How many references? (1-{imageCount})"
207
+ const count = getUserSliderValue();
208
+
209
+ // 3. Sample random images
210
+ const references = vref.sample(count);
211
+
212
+ // 4. Get user prompt
213
+ const prompt = getUserPrompt();
214
+
215
+ // 5. Send to your AI
216
+ await generateImage({
217
+ prompt: prompt,
218
+ referenceImages: references,
219
+ });
220
+ ```
221
+
222
+ **That's it.** ✅
223
+
224
+ ---
225
+
226
+ ## File Format
227
+
228
+ A `.vref` file is a ZIP container with:
229
+
230
+ ```
231
+ references.vref
232
+ ├── manifest.json (metadata)
233
+ ├── image1.png
234
+ ├── image2.jpg
235
+ └── image3.webp
236
+ ```
237
+
238
+ **Supported formats:** PNG, JPEG, WebP, GIF, AVIF
239
+
240
+ **Only images allowed.** Any other file type is rejected.
241
+
242
+ ### manifest.json
243
+
244
+ ```json
245
+ {
246
+ "version": "1.0.0",
247
+ "format": "VREF",
248
+ "fileName": "references.vref",
249
+ "imageCount": 24,
250
+ "images": [
251
+ {
252
+ "path": "image1.png",
253
+ "format": "png",
254
+ "size": 45678,
255
+ "width": 1920,
256
+ "height": 1080
257
+ }
258
+ ],
259
+ "createdAt": "2024-10-12T10:30:00.000Z",
260
+ "metadata": {
261
+ "description": "Collection of references",
262
+ "tags": ["style", "mood"],
263
+ "author": "Your Name",
264
+ "license": "CC-BY-4.0"
265
+ }
266
+ }
267
+ ```
268
+
269
+ ---
270
+
271
+ <div align="center">
272
+
273
+ ## Why VREF Will Win
274
+
275
+ </div>
276
+
277
+ ### 🎯 Solves a Real Problem
278
+ Everyone who uses AI image generation has struggled with describing visual concepts. VREF makes it trivial.
279
+
280
+ ### 🚀 Simple to Implement
281
+ ZIP + JSON. No complex dependencies. Works everywhere.
282
+
283
+ ### 🌍 Open Standard
284
+ No company owns it. Community-driven. Free forever.
285
+
286
+ ### 📦 Already Shipping
287
+ - ✅ npm package published
288
+ - ✅ Full TypeScript support
289
+ - ✅ CLI tool ready
290
+ - ✅ Documentation complete
291
+
292
+ ### 🇧🇷 Made in Brazil
293
+ Harpia AI Research is putting Brazil on the map of AI innovation.
294
+
295
+ ---
296
+
297
+ ### VREFWriter
298
+
299
+ ```typescript
300
+ class VREFWriter {
301
+ constructor(options: VREFCreateOptions);
302
+
303
+ addImageFromFile(filePath: string): void;
304
+ addImage(fileName: string, buffer: Buffer): void;
305
+ addImagesFromDirectory(dirPath: string, recursive?: boolean): void;
306
+
307
+ write(outputPath: string): void;
308
+ getImageCount(): number;
309
+ }
310
+ ```
311
+
312
+ ### VREFReader
313
+
314
+ ```typescript
315
+ class VREFReader {
316
+ static read(filePath: string, options?: VREFReadOptions): VREFReadResult;
317
+ static readManifest(filePath: string): VREFManifest;
318
+ static validate(filePath: string): { valid: boolean; errors: string[] };
319
+ }
320
+ ```
321
+
322
+ ### VREFReadResult
323
+
324
+ ```typescript
325
+ interface VREFReadResult {
326
+ manifest: VREFManifest;
327
+ images?: Map<string, Buffer>;
328
+ sample: (count: number) => Buffer[];
329
+ getImage: (path: string) => Buffer | undefined;
330
+ }
331
+ ```
332
+
333
+ Full API documentation: [TypeScript definitions](src/types.ts)
334
+
335
+ ---
336
+
337
+ ## Roadmap
338
+
339
+ ### Phase 1 ✅ (Done)
340
+ - Core library implementation
341
+ - CLI tool
342
+ - npm package published
343
+ - Full documentation
344
+
345
+ ### Phase 2 (In Progress)
346
+ - Community-created .vref files
347
+ - Platform integrations
348
+ - Example collections
349
+
350
+ ### Phase 3 (Future)
351
+ - Web-based .vref creator
352
+ - .vref marketplace
353
+ - Browser extensions
354
+ - Mobile support
355
+
356
+ ---
357
+
358
+ ## Join the Movement
359
+
360
+ VREF is just getting started. We need:
361
+
362
+ - **Platform developers**: Integrate VREF support
363
+ - **Creators**: Build and share .vref collections
364
+ - **Contributors**: Improve the library
365
+ - **Evangelists**: Spread the word
366
+
367
+ ---
368
+
369
+ ## Links
370
+
371
+ - **npm**: https://www.npmjs.com/package/@harpiaresearch/vref
372
+ - **GitHub**: https://github.com/Harpia-AI-Research/vref
373
+ - **Harpia AI Research**: https://harpiaresearch.cc
374
+ - **Issues**: https://github.com/Harpia-AI-Research/vref/issues
375
+
376
+ ---
377
+
378
+ ## License
379
+
380
+ This project is licensed under the **BSD 3-Clause License** - see the [LICENSE](LICENSE) file for details.
381
+
382
+ Copyright (c) 2024, Harpia AI Research
383
+
384
+ ---
385
+
386
+ ## Acknowledgments
387
+
388
+ VREF is an open standard for visual references in AI systems. Built to solve the gap between what creators envision and what they can describe in text.
389
+
390
+ **Technologies**: TypeScript, Node.js, adm-zip
391
+
392
+ ---
393
+
394
+ <div align="center">
395
+
396
+ **VREF** — Bridging vision and AI generation
397
+
398
+ <br><br>
399
+
400
+ [GitHub](https://github.com/Harpia-AI-Research/vref) •
401
+ [npm](https://www.npmjs.com/package/@harpiaresearch/vref) •
402
+ [Documentation](https://github.com/Harpia-AI-Research/vref#readme) •
403
+ [Issues](https://github.com/Harpia-AI-Research/vref/issues)
404
+
405
+ </div>
2
406
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
@@ -0,0 +1,22 @@
1
+ /**
2
+ * VREFReader - Reads .vref files
3
+ * Harpia AI Research
4
+ */
5
+ import { VREFManifest, VREFReadOptions, VREFReadResult } from './types';
6
+ export declare class VREFReader {
7
+ /**
8
+ * Read a .vref file
9
+ */
10
+ static read(filePath: string, options?: VREFReadOptions): VREFReadResult;
11
+ /**
12
+ * Read only the manifest without loading images
13
+ */
14
+ static readManifest(filePath: string): VREFManifest;
15
+ /**
16
+ * Validate a .vref file
17
+ */
18
+ static validate(filePath: string): {
19
+ valid: boolean;
20
+ errors: string[];
21
+ };
22
+ }
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ /**
3
+ * VREFReader - Reads .vref files
4
+ * Harpia AI Research
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.VREFReader = void 0;
44
+ const fs = __importStar(require("fs"));
45
+ const adm_zip_1 = __importDefault(require("adm-zip"));
46
+ class VREFReader {
47
+ /**
48
+ * Read a .vref file
49
+ */
50
+ static read(filePath, options = {}) {
51
+ if (!fs.existsSync(filePath)) {
52
+ throw new Error(`File not found: ${filePath}`);
53
+ }
54
+ const zip = new adm_zip_1.default(filePath);
55
+ const zipEntries = zip.getEntries();
56
+ // Find and parse manifest
57
+ const manifestEntry = zipEntries.find(entry => entry.entryName === 'manifest.json');
58
+ if (!manifestEntry) {
59
+ throw new Error('Invalid .vref file: manifest.json not found');
60
+ }
61
+ const manifestData = manifestEntry.getData().toString('utf8');
62
+ const manifest = JSON.parse(manifestData);
63
+ // Validate manifest
64
+ if (manifest.format !== 'VREF') {
65
+ throw new Error('Invalid .vref file: incorrect format identifier');
66
+ }
67
+ // Load images if requested
68
+ const images = new Map();
69
+ if (options.loadImages) {
70
+ for (const imageInfo of manifest.images) {
71
+ const entry = zipEntries.find(e => e.entryName === imageInfo.path);
72
+ if (entry) {
73
+ images.set(imageInfo.path, entry.getData());
74
+ }
75
+ }
76
+ }
77
+ // Helper function to get specific image
78
+ const getImage = (path) => {
79
+ if (images.has(path)) {
80
+ return images.get(path);
81
+ }
82
+ // Load on-demand if not already loaded
83
+ const entry = zipEntries.find(e => e.entryName === path);
84
+ if (entry) {
85
+ const buffer = entry.getData();
86
+ images.set(path, buffer);
87
+ return buffer;
88
+ }
89
+ return undefined;
90
+ };
91
+ // Helper function to sample N random images
92
+ const sample = (count) => {
93
+ const imagePaths = manifest.images.map(img => img.path);
94
+ const sampledPaths = [];
95
+ // Fisher-Yates shuffle for random sampling
96
+ const shuffled = [...imagePaths];
97
+ for (let i = shuffled.length - 1; i > 0; i--) {
98
+ const j = Math.floor(Math.random() * (i + 1));
99
+ [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
100
+ }
101
+ // Take first N
102
+ const selected = shuffled.slice(0, Math.min(count, shuffled.length));
103
+ // Load and return buffers
104
+ return selected.map(path => {
105
+ const buffer = getImage(path);
106
+ if (!buffer) {
107
+ throw new Error(`Failed to load image: ${path}`);
108
+ }
109
+ return buffer;
110
+ });
111
+ };
112
+ return {
113
+ manifest,
114
+ images: options.loadImages ? images : undefined,
115
+ sample,
116
+ getImage,
117
+ };
118
+ }
119
+ /**
120
+ * Read only the manifest without loading images
121
+ */
122
+ static readManifest(filePath) {
123
+ const result = VREFReader.read(filePath, { loadImages: false });
124
+ return result.manifest;
125
+ }
126
+ /**
127
+ * Validate a .vref file
128
+ */
129
+ static validate(filePath) {
130
+ const errors = [];
131
+ try {
132
+ if (!fs.existsSync(filePath)) {
133
+ errors.push('File does not exist');
134
+ return { valid: false, errors };
135
+ }
136
+ const zip = new adm_zip_1.default(filePath);
137
+ const zipEntries = zip.getEntries();
138
+ // Check for manifest
139
+ const manifestEntry = zipEntries.find(entry => entry.entryName === 'manifest.json');
140
+ if (!manifestEntry) {
141
+ errors.push('manifest.json not found');
142
+ return { valid: false, errors };
143
+ }
144
+ // Parse manifest
145
+ let manifest;
146
+ try {
147
+ const manifestData = manifestEntry.getData().toString('utf8');
148
+ manifest = JSON.parse(manifestData);
149
+ }
150
+ catch (error) {
151
+ errors.push('Failed to parse manifest.json');
152
+ return { valid: false, errors };
153
+ }
154
+ // Validate format
155
+ if (manifest.format !== 'VREF') {
156
+ errors.push('Invalid format identifier (expected "VREF")');
157
+ }
158
+ // Validate version
159
+ if (!manifest.version) {
160
+ errors.push('Missing version field');
161
+ }
162
+ // Validate image count
163
+ const actualImageCount = zipEntries.filter(e => e.entryName !== 'manifest.json').length;
164
+ if (manifest.imageCount !== actualImageCount) {
165
+ errors.push(`Image count mismatch: manifest says ${manifest.imageCount}, found ${actualImageCount}`);
166
+ }
167
+ // Validate all images listed in manifest exist
168
+ for (const imageInfo of manifest.images) {
169
+ const entry = zipEntries.find(e => e.entryName === imageInfo.path);
170
+ if (!entry) {
171
+ errors.push(`Image listed in manifest not found: ${imageInfo.path}`);
172
+ }
173
+ }
174
+ return {
175
+ valid: errors.length === 0,
176
+ errors,
177
+ };
178
+ }
179
+ catch (error) {
180
+ errors.push(`Unexpected error: ${error}`);
181
+ return { valid: false, errors };
182
+ }
183
+ }
184
+ }
185
+ exports.VREFReader = VREFReader;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * VREFWriter - Creates .vref files
3
+ * Harpia AI Research
4
+ */
5
+ import { VREFCreateOptions } from './types';
6
+ export declare class VREFWriter {
7
+ private images;
8
+ private options;
9
+ constructor(options: VREFCreateOptions);
10
+ /**
11
+ * Add an image from a file path
12
+ */
13
+ addImageFromFile(filePath: string): void;
14
+ /**
15
+ * Add an image from a buffer
16
+ */
17
+ addImage(fileName: string, buffer: Buffer): void;
18
+ /**
19
+ * Add multiple images from a directory
20
+ */
21
+ addImagesFromDirectory(dirPath: string, recursive?: boolean): void;
22
+ /**
23
+ * Write the .vref file
24
+ */
25
+ write(outputPath: string): void;
26
+ /**
27
+ * Validate image format
28
+ */
29
+ private isValidImageFormat;
30
+ /**
31
+ * Validate image buffer by checking magic bytes
32
+ */
33
+ private isValidImageBuffer;
34
+ /**
35
+ * Get image dimensions (basic implementation for PNG and JPEG)
36
+ */
37
+ private getImageDimensions;
38
+ /**
39
+ * Get current image count
40
+ */
41
+ getImageCount(): number;
42
+ /**
43
+ * Clear all images
44
+ */
45
+ clear(): void;
46
+ }
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ /**
3
+ * VREFWriter - Creates .vref files
4
+ * Harpia AI Research
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.VREFWriter = void 0;
44
+ const fs = __importStar(require("fs"));
45
+ const path = __importStar(require("path"));
46
+ const adm_zip_1 = __importDefault(require("adm-zip"));
47
+ const types_1 = require("./types");
48
+ class VREFWriter {
49
+ constructor(options) {
50
+ this.images = new Map();
51
+ this.options = options;
52
+ }
53
+ /**
54
+ * Add an image from a file path
55
+ */
56
+ addImageFromFile(filePath) {
57
+ if (!fs.existsSync(filePath)) {
58
+ throw new Error(`File not found: ${filePath}`);
59
+ }
60
+ const buffer = fs.readFileSync(filePath);
61
+ const fileName = path.basename(filePath);
62
+ this.addImage(fileName, buffer);
63
+ }
64
+ /**
65
+ * Add an image from a buffer
66
+ */
67
+ addImage(fileName, buffer) {
68
+ const ext = path.extname(fileName).toLowerCase().slice(1);
69
+ if (!this.isValidImageFormat(ext)) {
70
+ throw new Error(`Unsupported format: ${ext}. Only images are allowed: ${types_1.SUPPORTED_IMAGE_FORMATS.join(', ')}`);
71
+ }
72
+ // Validate that it's actually an image by checking magic bytes
73
+ if (!this.isValidImageBuffer(buffer, ext)) {
74
+ throw new Error(`File ${fileName} does not appear to be a valid ${ext} image`);
75
+ }
76
+ this.images.set(fileName, buffer);
77
+ }
78
+ /**
79
+ * Add multiple images from a directory
80
+ */
81
+ addImagesFromDirectory(dirPath, recursive = false) {
82
+ if (!fs.existsSync(dirPath)) {
83
+ throw new Error(`Directory not found: ${dirPath}`);
84
+ }
85
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
86
+ for (const entry of entries) {
87
+ const fullPath = path.join(dirPath, entry.name);
88
+ if (entry.isDirectory() && recursive) {
89
+ this.addImagesFromDirectory(fullPath, recursive);
90
+ }
91
+ else if (entry.isFile()) {
92
+ const ext = path.extname(entry.name).toLowerCase().slice(1);
93
+ if (this.isValidImageFormat(ext)) {
94
+ try {
95
+ this.addImageFromFile(fullPath);
96
+ }
97
+ catch (error) {
98
+ console.warn(`Skipping ${entry.name}: ${error}`);
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ /**
105
+ * Write the .vref file
106
+ */
107
+ write(outputPath) {
108
+ if (this.images.size === 0) {
109
+ throw new Error('No images added. Cannot create empty .vref file.');
110
+ }
111
+ const zip = new adm_zip_1.default();
112
+ const imageMetadataList = [];
113
+ // Add all images to ZIP
114
+ for (const [fileName, buffer] of this.images) {
115
+ zip.addFile(fileName, buffer);
116
+ const ext = path.extname(fileName).toLowerCase().slice(1);
117
+ const dimensions = this.getImageDimensions(buffer, ext);
118
+ imageMetadataList.push({
119
+ path: fileName,
120
+ format: ext,
121
+ size: buffer.length,
122
+ width: dimensions?.width,
123
+ height: dimensions?.height,
124
+ });
125
+ }
126
+ // Create manifest
127
+ const manifest = {
128
+ version: '1.0.0',
129
+ format: 'VREF',
130
+ fileName: path.basename(outputPath),
131
+ imageCount: this.images.size,
132
+ images: imageMetadataList,
133
+ createdAt: new Date().toISOString(),
134
+ metadata: {
135
+ description: this.options.description,
136
+ tags: this.options.tags,
137
+ author: this.options.author,
138
+ license: this.options.license,
139
+ ...this.options.metadata,
140
+ },
141
+ };
142
+ // Add manifest as JSON
143
+ zip.addFile('manifest.json', Buffer.from(JSON.stringify(manifest, null, 2)));
144
+ // Write ZIP file
145
+ zip.writeZip(outputPath);
146
+ }
147
+ /**
148
+ * Validate image format
149
+ */
150
+ isValidImageFormat(format) {
151
+ return types_1.SUPPORTED_IMAGE_FORMATS.includes(format);
152
+ }
153
+ /**
154
+ * Validate image buffer by checking magic bytes
155
+ */
156
+ isValidImageBuffer(buffer, format) {
157
+ if (buffer.length < 8)
158
+ return false;
159
+ switch (format.toLowerCase()) {
160
+ case 'png':
161
+ return buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47;
162
+ case 'jpg':
163
+ case 'jpeg':
164
+ return buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff;
165
+ case 'gif':
166
+ return buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46;
167
+ case 'webp':
168
+ return buffer[8] === 0x57 && buffer[9] === 0x45 && buffer[10] === 0x42 && buffer[11] === 0x50;
169
+ case 'avif':
170
+ // AVIF detection is more complex, but we can check for 'ftyp' box
171
+ const ftypCheck = buffer.toString('ascii', 4, 8);
172
+ return ftypCheck === 'ftyp';
173
+ default:
174
+ return false;
175
+ }
176
+ }
177
+ /**
178
+ * Get image dimensions (basic implementation for PNG and JPEG)
179
+ */
180
+ getImageDimensions(buffer, format) {
181
+ try {
182
+ if (format === 'png' && buffer.length >= 24) {
183
+ const width = buffer.readUInt32BE(16);
184
+ const height = buffer.readUInt32BE(20);
185
+ return { width, height };
186
+ }
187
+ if ((format === 'jpg' || format === 'jpeg') && buffer.length >= 4) {
188
+ // Basic JPEG dimension extraction (simplified)
189
+ // This is a simplified version; production code might use a library
190
+ let offset = 2;
191
+ while (offset < buffer.length) {
192
+ if (buffer[offset] !== 0xff)
193
+ break;
194
+ const marker = buffer[offset + 1];
195
+ offset += 2;
196
+ if (marker === 0xc0 || marker === 0xc2) {
197
+ const height = buffer.readUInt16BE(offset + 3);
198
+ const width = buffer.readUInt16BE(offset + 5);
199
+ return { width, height };
200
+ }
201
+ const segmentLength = buffer.readUInt16BE(offset);
202
+ offset += segmentLength;
203
+ }
204
+ }
205
+ }
206
+ catch (error) {
207
+ // If dimension extraction fails, just return undefined
208
+ return undefined;
209
+ }
210
+ return undefined;
211
+ }
212
+ /**
213
+ * Get current image count
214
+ */
215
+ getImageCount() {
216
+ return this.images.size;
217
+ }
218
+ /**
219
+ * Clear all images
220
+ */
221
+ clear() {
222
+ this.images.clear();
223
+ }
224
+ }
225
+ exports.VREFWriter = VREFWriter;
package/dist/cli.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * VREF CLI - Command line interface for creating .vref files
4
+ * Harpia AI Research
5
+ */
6
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * VREF CLI - Command line interface for creating .vref files
5
+ * Harpia AI Research
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const VREFWriter_1 = require("./VREFWriter");
44
+ function showHelp() {
45
+ console.log(`
46
+ ┌─────────────────────────────────────────────────┐
47
+ │ VREF CLI v1.0.0 │
48
+ │ by Harpia AI Research │
49
+ │ https://harpiaresearch.cc │
50
+ └─────────────────────────────────────────────────┘
51
+
52
+ Create .vref files from images
53
+
54
+ USAGE:
55
+ npx create-vref <input> [options]
56
+
57
+ ARGUMENTS:
58
+ <input> Path to image file or directory
59
+
60
+ OPTIONS:
61
+ -o, --output <path> Output .vref file path (default: output.vref)
62
+ -n, --name <name> Name for the reference pack
63
+ -d, --desc <text> Description of the reference pack
64
+ -t, --tags <tags> Comma-separated tags
65
+ -a, --author <name> Author name
66
+ -l, --license <lic> License (e.g., CC-BY-4.0, MIT)
67
+ -r, --recursive Include subdirectories
68
+ -h, --help Show this help
69
+
70
+ EXAMPLES:
71
+ # Create from single image
72
+ npx create-vref image.png -o references.vref
73
+
74
+ # Create from directory
75
+ npx create-vref ./images -o pack.vref -n "My Pack"
76
+
77
+ # With metadata
78
+ npx create-vref ./sprites -o rpg-sprites.vref \\
79
+ -n "RPG Sprites" \\
80
+ -d "Character sprites for RPG games" \\
81
+ -t "rpg,sprites,pixelart" \\
82
+ -a "Your Name" \\
83
+ -l "CC-BY-4.0"
84
+ `);
85
+ }
86
+ function parseArgs(args) {
87
+ const options = {
88
+ input: null,
89
+ output: 'output.vref',
90
+ name: null,
91
+ description: null,
92
+ tags: null,
93
+ author: null,
94
+ license: null,
95
+ recursive: false,
96
+ };
97
+ for (let i = 0; i < args.length; i++) {
98
+ const arg = args[i];
99
+ switch (arg) {
100
+ case '-h':
101
+ case '--help':
102
+ showHelp();
103
+ process.exit(0);
104
+ break;
105
+ case '-o':
106
+ case '--output':
107
+ options.output = args[++i];
108
+ break;
109
+ case '-n':
110
+ case '--name':
111
+ options.name = args[++i];
112
+ break;
113
+ case '-d':
114
+ case '--desc':
115
+ case '--description':
116
+ options.description = args[++i];
117
+ break;
118
+ case '-t':
119
+ case '--tags':
120
+ options.tags = args[++i].split(',').map((t) => t.trim());
121
+ break;
122
+ case '-a':
123
+ case '--author':
124
+ options.author = args[++i];
125
+ break;
126
+ case '-l':
127
+ case '--license':
128
+ options.license = args[++i];
129
+ break;
130
+ case '-r':
131
+ case '--recursive':
132
+ options.recursive = true;
133
+ break;
134
+ default:
135
+ if (!arg.startsWith('-')) {
136
+ options.input = arg;
137
+ }
138
+ break;
139
+ }
140
+ }
141
+ return options;
142
+ }
143
+ function main() {
144
+ const args = process.argv.slice(2);
145
+ if (args.length === 0) {
146
+ showHelp();
147
+ process.exit(0);
148
+ }
149
+ const options = parseArgs(args);
150
+ if (!options.input) {
151
+ console.error('❌ Error: No input specified');
152
+ console.log('Run "npx create-vref --help" for usage information');
153
+ process.exit(1);
154
+ }
155
+ if (!fs.existsSync(options.input)) {
156
+ console.error(`❌ Error: Input not found: ${options.input}`);
157
+ process.exit(1);
158
+ }
159
+ console.log('┌─────────────────────────────────────────────────┐');
160
+ console.log('│ VREF CLI v1.0.0 │');
161
+ console.log('│ by Harpia AI Research │');
162
+ console.log('└─────────────────────────────────────────────────┘\n');
163
+ try {
164
+ const fileName = options.name || path.basename(options.output, '.vref');
165
+ const writer = new VREFWriter_1.VREFWriter({
166
+ fileName: options.output,
167
+ description: options.description,
168
+ tags: options.tags,
169
+ author: options.author,
170
+ license: options.license,
171
+ });
172
+ console.log(`📂 Input: ${options.input}`);
173
+ const stat = fs.statSync(options.input);
174
+ if (stat.isDirectory()) {
175
+ console.log(`🔍 Scanning directory${options.recursive ? ' (recursive)' : ''}...`);
176
+ writer.addImagesFromDirectory(options.input, options.recursive);
177
+ }
178
+ else if (stat.isFile()) {
179
+ console.log('📄 Adding image...');
180
+ writer.addImageFromFile(options.input);
181
+ }
182
+ else {
183
+ throw new Error('Input must be a file or directory');
184
+ }
185
+ const imageCount = writer.getImageCount();
186
+ if (imageCount === 0) {
187
+ console.error('❌ Error: No valid images found');
188
+ process.exit(1);
189
+ }
190
+ console.log(`✅ Found ${imageCount} valid image${imageCount !== 1 ? 's' : ''}`);
191
+ console.log(`📦 Creating ${options.output}...`);
192
+ writer.write(options.output);
193
+ const stats = fs.statSync(options.output);
194
+ const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
195
+ console.log(`✅ Success! Created ${options.output} (${sizeMB} MB)`);
196
+ console.log('\n📋 Metadata:');
197
+ console.log(` Images: ${imageCount}`);
198
+ if (options.name)
199
+ console.log(` Name: ${options.name}`);
200
+ if (options.description)
201
+ console.log(` Description: ${options.description}`);
202
+ if (options.tags)
203
+ console.log(` Tags: ${options.tags.join(', ')}`);
204
+ if (options.author)
205
+ console.log(` Author: ${options.author}`);
206
+ if (options.license)
207
+ console.log(` License: ${options.license}`);
208
+ console.log('\n🚀 Share this file with AI platforms that support VREF!');
209
+ console.log(' Learn more: https://harpiaresearch.cc\n');
210
+ }
211
+ catch (error) {
212
+ console.error(`\n❌ Error: ${error.message}`);
213
+ process.exit(1);
214
+ }
215
+ }
216
+ main();
@@ -0,0 +1,10 @@
1
+ /**
2
+ * VREF (Visual Reference Format)
3
+ * Standardized container for curated visual references in AI image generation
4
+ *
5
+ * Harpia AI Research
6
+ * https://harpiaresearch.cc
7
+ */
8
+ export { VREFWriter } from './VREFWriter';
9
+ export { VREFReader } from './VREFReader';
10
+ export { VREFManifest, VREFCreateOptions, VREFReadOptions, VREFReadResult, ImageMetadata, SupportedImageFormat, SUPPORTED_IMAGE_FORMATS, } from './types';
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ /**
3
+ * VREF (Visual Reference Format)
4
+ * Standardized container for curated visual references in AI image generation
5
+ *
6
+ * Harpia AI Research
7
+ * https://harpiaresearch.cc
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.SUPPORTED_IMAGE_FORMATS = exports.VREFReader = exports.VREFWriter = void 0;
11
+ var VREFWriter_1 = require("./VREFWriter");
12
+ Object.defineProperty(exports, "VREFWriter", { enumerable: true, get: function () { return VREFWriter_1.VREFWriter; } });
13
+ var VREFReader_1 = require("./VREFReader");
14
+ Object.defineProperty(exports, "VREFReader", { enumerable: true, get: function () { return VREFReader_1.VREFReader; } });
15
+ var types_1 = require("./types");
16
+ Object.defineProperty(exports, "SUPPORTED_IMAGE_FORMATS", { enumerable: true, get: function () { return types_1.SUPPORTED_IMAGE_FORMATS; } });
@@ -0,0 +1,96 @@
1
+ /**
2
+ * VREF (Visual Reference Format) Type Definitions
3
+ * Harpia AI Research
4
+ */
5
+ /**
6
+ * VREF Manifest structure
7
+ * Automatically generated and included in every .vref file
8
+ */
9
+ export interface VREFManifest {
10
+ /** VREF format version (semver) */
11
+ version: string;
12
+ /** Format identifier */
13
+ format: 'VREF';
14
+ /** ZIP compression version (if applicable) */
15
+ zipVersion?: string;
16
+ /** Name of the .vref file */
17
+ fileName: string;
18
+ /** Total number of images in the container */
19
+ imageCount: number;
20
+ /** Array of image metadata */
21
+ images: ImageMetadata[];
22
+ /** ISO 8601 timestamp of creation */
23
+ createdAt: string;
24
+ /** Optional metadata */
25
+ metadata?: {
26
+ /** Description of the reference pack */
27
+ description?: string;
28
+ /** Tags for categorization */
29
+ tags?: string[];
30
+ /** Author information */
31
+ author?: string;
32
+ /** License information */
33
+ license?: string;
34
+ /** Any additional custom fields */
35
+ [key: string]: any;
36
+ };
37
+ }
38
+ /**
39
+ * Metadata for individual images within the VREF
40
+ */
41
+ export interface ImageMetadata {
42
+ /** Relative path within the .vref archive */
43
+ path: string;
44
+ /** Image format (png, jpg, jpeg, webp, gif, avif) */
45
+ format: string;
46
+ /** File size in bytes */
47
+ size: number;
48
+ /** Image width in pixels */
49
+ width?: number;
50
+ /** Image height in pixels */
51
+ height?: number;
52
+ }
53
+ /**
54
+ * Options for creating a VREF file
55
+ */
56
+ export interface VREFCreateOptions {
57
+ /** Name for the output .vref file */
58
+ fileName: string;
59
+ /** Optional description */
60
+ description?: string;
61
+ /** Optional tags */
62
+ tags?: string[];
63
+ /** Optional author */
64
+ author?: string;
65
+ /** Optional license */
66
+ license?: string;
67
+ /** Additional metadata */
68
+ metadata?: Record<string, any>;
69
+ }
70
+ /**
71
+ * Options for reading a VREF file
72
+ */
73
+ export interface VREFReadOptions {
74
+ /** Whether to extract images to memory */
75
+ loadImages?: boolean;
76
+ /** Validate image formats */
77
+ validate?: boolean;
78
+ }
79
+ /**
80
+ * Result of reading a VREF file
81
+ */
82
+ export interface VREFReadResult {
83
+ /** Parsed manifest */
84
+ manifest: VREFManifest;
85
+ /** Image buffers (if loadImages: true) */
86
+ images?: Map<string, Buffer>;
87
+ /** Get a random sample of N images */
88
+ sample: (count: number) => Buffer[];
89
+ /** Get specific image by path */
90
+ getImage: (path: string) => Buffer | undefined;
91
+ }
92
+ /**
93
+ * Supported image formats
94
+ */
95
+ export declare const SUPPORTED_IMAGE_FORMATS: readonly ["png", "jpg", "jpeg", "webp", "gif", "avif"];
96
+ export type SupportedImageFormat = typeof SUPPORTED_IMAGE_FORMATS[number];
package/dist/types.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ /**
3
+ * VREF (Visual Reference Format) Type Definitions
4
+ * Harpia AI Research
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.SUPPORTED_IMAGE_FORMATS = void 0;
8
+ /**
9
+ * Supported image formats
10
+ */
11
+ exports.SUPPORTED_IMAGE_FORMATS = [
12
+ 'png',
13
+ 'jpg',
14
+ 'jpeg',
15
+ 'webp',
16
+ 'gif',
17
+ 'avif'
18
+ ];
package/package.json CHANGED
@@ -1,6 +1,48 @@
1
1
  {
2
2
  "name": "@harpiaresearch/vref",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.1",
4
+ "description": "Visual Reference Format - Standardized container for curated visual references in AI image generation",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist/**/*",
9
+ "README.md",
10
+ "LICENSE"
11
+ ],
12
+ "bin": {
13
+ "create-vref": "./dist/cli.js",
14
+ "vref": "./dist/cli.js"
15
+ },
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "dev": "tsc --watch",
19
+ "test": "node --test",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "vref",
24
+ "visual-reference",
25
+ "ai",
26
+ "image-generation",
27
+ "midjourney",
28
+ "stable-diffusion",
29
+ "harpia"
30
+ ],
31
+ "author": "Harpia AI Research",
32
+ "license": "BSD-3-Clause",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/Harpia-AI-Research/vref"
36
+ },
37
+ "dependencies": {
38
+ "adm-zip": "^0.5.10"
39
+ },
40
+ "devDependencies": {
41
+ "@types/adm-zip": "^0.5.5",
42
+ "@types/node": "^20.0.0",
43
+ "typescript": "^5.3.0"
44
+ },
45
+ "engines": {
46
+ "node": ">=18.0.0"
47
+ }
48
+ }