rng-with-intention 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Todd Wilson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,123 @@
1
+ # rng-with-intention
2
+
3
+ A random number generator that uses human intention as a seed, designed for divination and contemplative practices.
4
+
5
+ ## Philosophy
6
+
7
+ Digital randomness often feels hollow in spiritual or contemplative contexts because it lacks the intentionality present in physical practices like shuffling tarot cards or casting runes. This library bridges that gap by:
8
+
9
+ 1. **Using intention as the primary input** - Your words, thoughts, or questions become part of the randomness
10
+ 2. **Capturing the precise moment** - The exact millisecond you submit your intention matters
11
+ 3. **Remaining ephemeral** - Intentions are never stored, only used to seed that single moment
12
+ 4. **Adding true randomness** - System entropy ensures the same intention at different moments produces different results
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install rng-with-intention
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ### Basic usage
23
+
24
+ ```javascript
25
+ import { RngWithIntention } from 'rng-with-intention';
26
+
27
+ const rngi = new RngWithIntention();
28
+
29
+ // Draw a single card from a 78-card tarot deck
30
+ const result = rngi.draw("What do I need to know today?", 78);
31
+ console.log(result);
32
+ // { index: 42, timestamp: '2024-12-31T09:47:23.847Z' }
33
+ ```
34
+
35
+ ### Drawing multiple values
36
+
37
+ ```javascript
38
+ // Draw a 3-card spread
39
+ const spread = rngi.drawMultiple("Past, present, future", 78, 3);
40
+ console.log(spread);
41
+ // { indices: [5, 32, 67], timestamp: '2024-12-31T09:47:23.847Z' }
42
+
43
+ // Draw unique cards (no duplicates)
44
+ const uniqueSpread = rngi.drawMultiple("Celtic Cross", 78, 10, false);
45
+ ```
46
+
47
+ ### Configuration options
48
+
49
+ ```javascript
50
+ // Disable timestamp (makes draws deterministic for same intention)
51
+ const deterministicRng = new RngWithIntention({
52
+ includeTimestamp: false,
53
+ includeEntropy: false
54
+ });
55
+
56
+ // Same intention will always produce same result
57
+ const result1 = deterministicRng.draw("test", 100);
58
+ const result2 = deterministicRng.draw("test", 100);
59
+ // result1.index === result2.index (always true)
60
+ ```
61
+
62
+ ## API
63
+
64
+ ### `new RngWithIntention(options)`
65
+
66
+ Create a new instance with optional configuration.
67
+
68
+ **Options:**
69
+ - `includeTimestamp` (boolean, default: `true`) - Include timestamp in seed
70
+ - `includeEntropy` (boolean, default: `true`) - Include cryptographic randomness in seed
71
+
72
+ ### `draw(intention, max)`
73
+
74
+ Draw a single random number.
75
+
76
+ **Parameters:**
77
+ - `intention` (string, required) - Your intention, question, or focus
78
+ - `max` (number, required) - Maximum value (exclusive, returns 0 to max-1)
79
+
80
+ **Returns:**
81
+ - `{ index: number, timestamp: string }`
82
+
83
+ ### `drawMultiple(intention, max, count, allowDuplicates)`
84
+
85
+ Draw multiple random numbers with a single intention.
86
+
87
+ **Parameters:**
88
+ - `intention` (string, required) - Your intention
89
+ - `max` (number, required) - Maximum value for each draw
90
+ - `count` (number, required) - Number of values to draw
91
+ - `allowDuplicates` (boolean, default: `true`) - Whether to allow repeated indices
92
+
93
+ **Returns:**
94
+ - `{ indices: number[], timestamp: string }`
95
+
96
+ ## Use Cases
97
+
98
+ - **Tarot readings** - Digital card draws with intentionality
99
+ - **Oracle cards** - Any deck-based divination system
100
+ - **I Ching** - Hexagram generation
101
+ - **Rune casting** - Random rune selection
102
+ - **Creative constraints** - Intentional prompts for writing, art, music
103
+ - **Journaling** - Daily prompts seeded by your current state
104
+ - **Decision making** - When you need the universe to weigh in
105
+
106
+ ## How It Works
107
+
108
+ 1. You provide an intention (any string)
109
+ 2. The exact timestamp is captured (down to milliseconds)
110
+ 3. System entropy is added (cryptographic randomness)
111
+ 4. These are combined and hashed with SHA-256
112
+ 5. The hash is converted to a number in your desired range
113
+ 6. The intention is discarded (never stored)
114
+
115
+ The result is randomness that feels **shaped by your intention** rather than purely mechanical.
116
+
117
+ ## License
118
+
119
+ MIT
120
+
121
+ ## Contributing
122
+
123
+ Issues and pull requests welcome! This library aims to remain simple and focused.
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "rng-with-intention",
3
+ "version": "0.1.0",
4
+ "description": "A random number generator that uses human intention as a seed, designed for divination and contemplative practices",
5
+ "main": "src/index.js",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": "./src/index.js"
9
+ },
10
+ "files": [
11
+ "src",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "test": "node --test test/**/*.test.js"
17
+ },
18
+ "keywords": [
19
+ "random",
20
+ "rng",
21
+ "intention",
22
+ "divination",
23
+ "tarot",
24
+ "contemplative",
25
+ "seed"
26
+ ],
27
+ "author": "Todd Wilson",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/w8s/rng-with-intention.git"
32
+ },
33
+ "engines": {
34
+ "node": ">=18.0.0"
35
+ }
36
+ }
@@ -0,0 +1,123 @@
1
+ import crypto from 'crypto';
2
+
3
+ /**
4
+ * RngWithIntention - A random number generator seeded by human intention
5
+ *
6
+ * This class creates random numbers using a combination of:
7
+ * - User intention (as text or any string)
8
+ * - Precise timestamp (when intention is submitted)
9
+ * - System entropy (cryptographic randomness)
10
+ *
11
+ * The intention is never stored - it exists only as the seed for that moment.
12
+ */
13
+ export class RngWithIntention {
14
+ /**
15
+ * Create a new RngWithIntention instance
16
+ * @param {Object} options - Configuration options
17
+ * @param {boolean} options.includeTimestamp - Include timestamp in seed (default: true)
18
+ * @param {boolean} options.includeEntropy - Include system entropy in seed (default: true)
19
+ */
20
+ constructor(options = {}) {
21
+ this.options = {
22
+ includeTimestamp: true,
23
+ includeEntropy: true,
24
+ ...options
25
+ };
26
+ }
27
+
28
+ /**
29
+ * Draw a random number based on intention
30
+ * @param {string} intention - The user's intention (any text)
31
+ * @param {number} max - Maximum value (exclusive, returns 0 to max-1)
32
+ * @returns {Object} { index: number, timestamp: string }
33
+ */
34
+ draw(intention, max) {
35
+ if (!intention || typeof intention !== 'string') {
36
+ throw new Error('Intention must be a non-empty string');
37
+ }
38
+
39
+ if (!Number.isInteger(max) || max <= 0) {
40
+ throw new Error('Max must be a positive integer');
41
+ }
42
+
43
+ // Capture the exact moment
44
+ const timestamp = new Date().toISOString();
45
+
46
+ // Build the seed from components
47
+ let seedComponents = [intention];
48
+
49
+ if (this.options.includeTimestamp) {
50
+ seedComponents.push(timestamp);
51
+ }
52
+
53
+ if (this.options.includeEntropy) {
54
+ // Add cryptographic randomness
55
+ const entropy = crypto.randomBytes(16).toString('hex');
56
+ seedComponents.push(entropy);
57
+ }
58
+
59
+ // Create seed (ephemeral - not stored)
60
+ const seedString = seedComponents.join('::');
61
+
62
+ // Hash the seed to get deterministic bytes
63
+ const hash = crypto.createHash('sha256').update(seedString).digest();
64
+
65
+ // Convert hash bytes to a number in range [0, max)
66
+ // Use multiple bytes to reduce modulo bias
67
+ const bytes = hash.readUInt32BE(0);
68
+ const index = bytes % max;
69
+
70
+ return {
71
+ index,
72
+ timestamp
73
+ };
74
+ }
75
+
76
+ /**
77
+ * Draw multiple random numbers with a single intention
78
+ * @param {string} intention - The user's intention
79
+ * @param {number} max - Maximum value for each draw
80
+ * @param {number} count - Number of values to draw
81
+ * @param {boolean} allowDuplicates - Whether to allow the same index multiple times (default: true)
82
+ * @returns {Object} { indices: number[], timestamp: string }
83
+ */
84
+ drawMultiple(intention, max, count, allowDuplicates = true) {
85
+ if (!Number.isInteger(count) || count <= 0) {
86
+ throw new Error('Count must be a positive integer');
87
+ }
88
+
89
+ if (!allowDuplicates && count > max) {
90
+ throw new Error('Cannot draw more unique values than max allows');
91
+ }
92
+
93
+ const timestamp = new Date().toISOString();
94
+ const indices = [];
95
+ const used = new Set();
96
+
97
+ for (let i = 0; i < count; i++) {
98
+ // Modify intention slightly for each draw to ensure different results
99
+ const modifiedIntention = `${intention}::draw${i}`;
100
+ const result = this.draw(modifiedIntention, max);
101
+
102
+ if (allowDuplicates) {
103
+ indices.push(result.index);
104
+ } else {
105
+ // Keep drawing until we get an unused index
106
+ let attempts = 0;
107
+ let index = result.index;
108
+ while (used.has(index) && attempts < max * 2) {
109
+ const retry = this.draw(`${modifiedIntention}::retry${attempts}`, max);
110
+ index = retry.index;
111
+ attempts++;
112
+ }
113
+ used.add(index);
114
+ indices.push(index);
115
+ }
116
+ }
117
+
118
+ return {
119
+ indices,
120
+ timestamp
121
+ };
122
+ }
123
+ }
package/src/index.js ADDED
@@ -0,0 +1 @@
1
+ export { RngWithIntention } from './RngWithIntention.js';