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 +21 -0
- package/README.md +123 -0
- package/package.json +36 -0
- package/src/RngWithIntention.js +123 -0
- package/src/index.js +1 -0
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';
|