├── p5js ├── .minify.json ├── build.js ├── Makefile ├── input │ ├── 01_fflate_callback.js │ └── 02_main.js ├── README.md └── page-structure.html ├── threejs ├── .minify.json ├── build.js ├── Makefile ├── compressed-inputs │ ├── 01_dim_fflate.js │ └── 02_main.min.js ├── README.md ├── page-structure.html └── 02_main.js ├── compress-html ├── .minify.json ├── build.js ├── Makefile ├── README.md ├── page-structure.html ├── onepage │ ├── index.html │ └── indexupdatedui.html └── examples │ └── 7345219 Space Shooter compressed.html ├── browserUI ├── README.md ├── template.html ├── __test_output_p5js.html ├── __test_output_threejs.html └── index.html └── README.md /p5js/.minify.json: -------------------------------------------------------------------------------- 1 | { 2 | "js": { 3 | "removeUnusedVariables": false 4 | } 5 | } -------------------------------------------------------------------------------- /threejs/.minify.json: -------------------------------------------------------------------------------- 1 | { 2 | "js": { 3 | "removeUnusedVariables": false 4 | } 5 | } -------------------------------------------------------------------------------- /compress-html/.minify.json: -------------------------------------------------------------------------------- 1 | { 2 | "js": { 3 | "removeUnusedVariables": false 4 | } 5 | } -------------------------------------------------------------------------------- /p5js/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const page_structure = fs.readFileSync('page-structure.html', {encoding:'utf8'}); 3 | const src_compressed = fs.readFileSync('src-compressed-string.base64', {encoding:'utf8'}).trim() 4 | const page01 = page_structure.replace('SRC_COMPRESSED_STRING', src_compressed); 5 | console.log(page01); 6 | -------------------------------------------------------------------------------- /threejs/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const page_structure = fs.readFileSync('page-structure.html', {encoding:'utf8'}); 3 | const src_compressed = fs.readFileSync('src-compressed-string.base64', {encoding:'utf8'}).trim() 4 | const page01 = page_structure.replace('SRC_COMPRESSED_STRING', src_compressed); 5 | console.log(page01); 6 | -------------------------------------------------------------------------------- /compress-html/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const page_structure = fs.readFileSync('page-structure.html', {encoding:'utf8'}); 3 | const src_compressed = fs.readFileSync('src-compressed-string.base64', {encoding:'utf8'}).trim() 4 | const page01 = page_structure.replace('SRC_COMPRESSED_STRING', src_compressed); 5 | console.log(page01); 6 | -------------------------------------------------------------------------------- /p5js/Makefile: -------------------------------------------------------------------------------- 1 | all: src-compressed-string.base64 index.html 2 | 3 | index.html: src-compressed-string.base64 build.js page-structure.html 4 | node build.js >$@ 5 | 6 | src-compressed-string.base64: input/ 7 | cat input/* | gzip -9 -c | base64 | tr -d '\n' >$@ 8 | 9 | clean: 10 | rm -f src-compressed-string.base64 index.html 11 | -------------------------------------------------------------------------------- /compress-html/Makefile: -------------------------------------------------------------------------------- 1 | all: src-compressed-string.base64 index.html 2 | 3 | index.html: src-compressed-string.base64 build.js page-structure.html 4 | node build.js >$@ 5 | 6 | src-compressed-string.base64: input/ 7 | cat input/* | gzip -9 -c | base64 | tr -d '\n' >$@ 8 | 9 | clean: 10 | rm -f src-compressed-string.base64 index.html 11 | -------------------------------------------------------------------------------- /p5js/input/01_fflate_callback.js: -------------------------------------------------------------------------------- 1 | function fflateCallback2() { 2 | const p5Code = fflate.strFromU8(fflate.gunzipSync(new Uint8Array(Array.from(atob(d3)).map((char) => char.charCodeAt(0))))); 3 | 4 | const newScript = document.createElement('script'); 5 | newScript.innerHTML = [p5Code].join(";\n"); 6 | document.body.appendChild(newScript); 7 | } -------------------------------------------------------------------------------- /threejs/Makefile: -------------------------------------------------------------------------------- 1 | all: src-compressed-string.base64 index.html 2 | 3 | index.html: src-compressed-string.base64 build.js page-structure.html 4 | node build.js >$@ 5 | 6 | src-compressed-string.base64: compressed-inputs/ 7 | cat compressed-inputs/* | gzip -9 -c | base64 | tr -d '\n' >$@ 8 | 9 | clean: 10 | rm -f src-compressed-string.base64 index.html 11 | -------------------------------------------------------------------------------- /p5js/input/02_main.js: -------------------------------------------------------------------------------- 1 | let z; 2 | 3 | function setup() { 4 | createCanvas(720, 400); 5 | stroke(255); 6 | noLoop(); 7 | z = height * 0.5; 8 | } 9 | 10 | function draw() { 11 | background(0); 12 | z = z - 4; 13 | if (z < 0) { 14 | z = height; 15 | } 16 | line(0, z, width, z); 17 | } 18 | 19 | function mousePressed() { 20 | redraw(); 21 | } -------------------------------------------------------------------------------- /p5js/README.md: -------------------------------------------------------------------------------- 1 | ### Use p5.js 2 | 3 | 1. Navigate to the `p5js` directory with `cd ../p5js`. 4 | 2. Put your js code in `input/02_main.js`. 5 | 3. Run `make clean && make` in the terminal. 6 | 4. Your final file will be `index.html`. 7 | 5. To check if `index.html` file works locally, open `index.html` and search and replace "fetch(/content/" with "fetch(https://ordinals.com/content/" (2 places). 8 | -------------------------------------------------------------------------------- /compress-html/README.md: -------------------------------------------------------------------------------- 1 | ### Compress HTML 2 | 3 | 1. Navigate to the `compress-html` directory with `cd compress-html`. 4 | 2. Place your `.html` file in the `input` directory. 5 | 3. Run `make clean && make` in the terminal. 6 | 4. Your compressed file will be `index.html`. 7 | 5. To check if `index.html` file works locally, open `index.html` and search and replace "fetch(/content/" with "fetch(https://ordinals.com/content/". -------------------------------------------------------------------------------- /threejs/compressed-inputs/01_dim_fflate.js: -------------------------------------------------------------------------------- 1 | function fflateCallback2() { 2 | const dimCode = fflate.strFromU8(fflate.gunzipSync(new Uint8Array(Array.from(atob(d3)).map((char) => char.charCodeAt(0))))); 3 | const threeJsCode = dimCode.split('\n')[5]; 4 | 5 | const ocmCallbackScript = "ocmCallback();"; 6 | 7 | const newScript = document.createElement('script'); 8 | newScript.innerHTML = [threeJsCode, ocmCallbackScript].join(";\n"); 9 | document.body.appendChild(newScript); 10 | } -------------------------------------------------------------------------------- /threejs/README.md: -------------------------------------------------------------------------------- 1 | ### Use Three.js 2 | 3 | 1. Navigate to the `threejs` directory with `cd ../threejs`. 4 | 2. Minify your `02_main.js` file and save it as `compressed-inputs/02_main.min.js`. 5 | - If you have `minify` installed, run `minify 02_main.js > compressed-inputs/02_main.min.js` in the terminal. 6 | - If you don't have `minify`, just put the js code in `compressed-inputs/02_main.min.js` directly. 7 | 3. Run `make clean && make` in the terminal. 8 | 4. Your final file will be `index.html`. 9 | 5. To check if `index.html` file works locally, open `index.html` and search and replace "fetch(/content/" with "fetch(https://ordinals.com/content/". 10 | -------------------------------------------------------------------------------- /browserUI/README.md: -------------------------------------------------------------------------------- 1 | ### Browser UI 2 | 3 | This folder provides an in-browser tool for assembling a compressed HTML page. 4 | It uses the same on-chain libraries as the command line utilities but lets you 5 | experiment without running `make`. 6 | 7 | #### Usage 8 | 9 | 1. Open `index.html` in your browser. 10 | 2. Select the libraries you want to include. 11 | 3. Paste or write your JavaScript/HTML code. 12 | 4. Click **Compile** to generate a ready-to-inscribe page. 13 | 14 | The generated page is based on `template.html`. For offline testing you can set 15 | `isTesting` to `true` in that file, which prepends `https://ordinals.com` to 16 | fetch calls. 17 | 18 | -------------------------------------------------------------------------------- /threejs/compressed-inputs/02_main.min.js: -------------------------------------------------------------------------------- 1 | function ocmCallback(){var a=new THREE.WebGLRenderer({antialias:!0}),c=new THREE.Scene(),d=new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 100),f=new THREE.PointLight(0xffffff, 1, 100),g=new THREE.TorusKnotGeometry(10, 2, 200, 20, 6, 8),h=new THREE.MeshStandardMaterial({color:0xffffaa,wireframe:!1}),i=new THREE.Mesh(g, h);a.setSize(window.innerWidth,window.innerHeight);a.shadowMap.enabled=!0;d.position.set(0,0.6,50.5);c.add(new THREE.AmbientLight(0x330066, 0.5));f.position.set(1,1,1);c.add(f);c.add(i);c.add(i);function j(){requestAnimationFrame(j);i.rotation.x+=0.01;i.rotation.y+=0.01;a.render(c,d)}j();document.querySelector("#scene").appendChild(a.domElement)} 2 | -------------------------------------------------------------------------------- /threejs/page-structure.html: -------------------------------------------------------------------------------- 1 |
17 | -------------------------------------------------------------------------------- /p5js/page-structure.html: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /compress-html/page-structure.html: -------------------------------------------------------------------------------- 1 |
21 | -------------------------------------------------------------------------------- /threejs/02_main.js: -------------------------------------------------------------------------------- 1 | function ocmCallback() { 2 | const renderer = new THREE.WebGLRenderer({ antialias: !0 }); 3 | renderer.setSize(window.innerWidth, window.innerHeight); 4 | renderer.shadowMap.enabled = true; 5 | 6 | const scene = new THREE.Scene(); 7 | 8 | const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 100); 9 | camera.position.set(0, 0.6, 50.5); 10 | 11 | const ambientLight = new THREE.AmbientLight(0x330066, 0.5); 12 | scene.add(ambientLight); 13 | 14 | const light = new THREE.PointLight(0xffffff, 1, 100); 15 | light.position.set(1, 1, 1); 16 | scene.add(light); 17 | 18 | const geometry = new THREE.TorusKnotGeometry(10, 2, 200, 20, 6, 8); 19 | const material = new THREE.MeshStandardMaterial({ color: 0xffffaa, wireframe: false }); 20 | const torusKnot = new THREE.Mesh(geometry, material); scene.add(torusKnot); 21 | 22 | scene.add(torusKnot); 23 | 24 | function animate() { 25 | requestAnimationFrame( animate ); 26 | 27 | torusKnot.rotation.x += 0.01; 28 | torusKnot.rotation.y += 0.01; 29 | 30 | renderer.render( scene, camera ); 31 | } 32 | 33 | animate(); 34 | 35 | document.querySelector("#scene").appendChild(renderer.domElement); 36 | } 37 | -------------------------------------------------------------------------------- /compress-html/onepage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | single page compression pipeline 5 | 6 | 7 | 8 | 9 | 46 | 49 |
50 |
51 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /browserUI/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | 24 |
25 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /browserUI/__test_output_p5js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | 24 |
25 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OCM Dimensions 2 | 3 | Welcome to OCM Dimensions! 4 | 5 | [OCM Dimensions](https://onchainmonkey.com/ocm-dimensions) is a high-resolution, 3D animated and generative ordinal collection, making it a pioneer among collections on Bitcoin since its inscription in February 2023. Dimensions innovates in the following areas: 6 | 7 | 1. Recursion and composability 8 | 2. Code libraries - compression, Three.js, p5.js - the main subject of this GitHub repo, using these libraries, anyone can 9 | create art on Bitcoin. It's completely open, decentralized, and the art renders automatically on all Ord explorers from 10 | using the on-chain libraries. 11 | 3. Generative inscriptions 12 | 4. File size - OCM Dimensions does all this in less than 500 bytes per inscription 13 | 5. Provenance and parent-child 14 | 6. On-chain randomization and reveal with a fair launch 15 | 7. Reinscription 16 | 8. 3D animated and interactive 17 | 9. Streaming from a satoshi, and adjusts to screen resolution and aspect ratio 18 | 10. Special sats and sat manipulation art - the OCM Collection was inscribed on sequential block 78 sats that matched the 19 | numbers in the collection, and was a parent-child cursed collection. 20 | 21 | Read more [about OCM Dimensions.](https://onchainmonkey.medium.com/ocm-dimensions-unveiling-the-many-dimensions-of-bitcoin-ordinals-c850688db68e) 22 | 23 | This GitHub repository for OCM Dimensions is a suite of tools aimed at helping creators save space on the Bitcoin blockchain by compressing their HTML, and empower creators with the powerful libraries of Three.js, and p5.js which we inscribed on Bitcoin. By leveraging the Dimensions art, we're making it possible to have more power inscribing on Bitcoin, with no changes needed to the Ordinal protocol. 24 | 25 | This toolset comprises several utilities: 26 | 27 | 1. Compress HTML 28 | 2. Use Three.js 29 | 3. Use p5.js 30 | 4. Browser UI 31 | 32 | ## Repository Structure 33 | 34 | - **compress-html/** – Compress a single HTML file using gzip and base64. 35 | - **threejs/** – Helper scripts for Three.js projects. 36 | - **p5js/** – Helper scripts for p5.js projects. 37 | - **browserUI/** – In-browser interface to bundle code with selected libraries. 38 | - **compress-html/examples/** – Samples demonstrating larger pieces of content. 39 | - **compress-html/onepage/** – Example output from the browser UI. 40 | 41 | Each directory includes a README with specific build instructions. 42 | 43 | Let's walk through how to use each of them. 44 | 45 | ## Prerequisites 46 | You will need the following installed on your machine: 47 | - Node.js and npm. You can download these from [here](https://nodejs.org/). 48 | - `make` command. This is usually pre-installed on Unix-based systems. For Windows, you can use a utility like [Make for Windows](http://gnuwin32.sourceforge.net/packages/make.htm). 49 | 50 | ## Installation 51 | You can download the tools directly from this GitHub repository. Simply click on the 'Code' button on this page and then click 'Download ZIP'. Once downloaded, unzip the file and navigate to the resulting directory in your terminal. 52 | 53 | If you have `git` installed, you can also clone this repository by running: 54 | 55 | ```bash 56 | git clone https://github.com/metagood/OCM-Dimensions.git 57 | cd OCM-Dimensions 58 | ``` 59 | 60 | ## Usage 61 | ### Compress HTML 62 | 63 | 1. Navigate to the `compress-html` directory with `cd compress-html`. 64 | 2. Place your `.html` file in the `input` directory. 65 | 3. Run `make clean && make` in the terminal. 66 | 4. Your compressed file will be `index.html`. 67 | 5. To check if `index.html` file works locally, open `index.html` and search and replace "fetch(/content/" with "fetch(https://ordinals.com/content/". 68 | 69 | ### Use Three.js 70 | 71 | 1. Navigate to the `threejs` directory with `cd ../threejs`. 72 | 2. Minify your `02_main.js` file and save it as `compressed-inputs/02_main.min.js`. 73 | - If you have `minify` installed, run `minify 02_main.js > compressed-inputs/02_main.min.js` in the terminal. 74 | - If you don't have `minify`, just put the js code in `compressed-inputs/02_main.min.js` directly. 75 | 3. Run `make clean && make` in the terminal. 76 | 4. Your final file will be `index.html`. 77 | 5. To check if `index.html` file works locally, open `index.html` and search and replace "fetch(/content/" with "fetch(https://ordinals.com/content/". 78 | 79 | ### Use p5.js 80 | 81 | 1. Navigate to the `p5js` directory with `cd ../p5js`. 82 | 2. Put your js code in `input/02_main.js`. 83 | 3. Run `make clean && make` in the terminal. 84 | 4. Your final file will be `index.html`. 85 | 5. To check if `index.html` file works locally, open `index.html` and search and replace "fetch(/content/" with "fetch(https://ordinals.com/content/" (2 places). 86 | 87 | ## Inscribing Your Art 88 | With your HTML, Three.js, or p5.js file compressed into `index.html`, you're ready to inscribe your art on the Bitcoin blockchain. Thanks to the OCM Dimensions, your art will be stored in a highly efficient manner, saving valuable space and allowing for more creativity. Happy coding and inscribing! 89 | 90 | ## Feedback 91 | We appreciate your feedback and suggestions. Please create an issue in the GitHub issue tracker. 92 | -------------------------------------------------------------------------------- /browserUI/__test_output_threejs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 25 | 26 |
27 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /compress-html/onepage/indexupdatedui.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | single page compression pipeline 5 | 6 | 7 | 8 | 9 | 10 | 11 | 54 |
55 |

Dimensions Compressor

56 | 57 | 58 |
59 | Include a library: 60 | 64 | 68 | 72 |
73 |
74 | Settings: 75 | 79 |
80 | 81 | 82 | 85 | 86 | 87 | 88 | powered by 89 | 90 | 91 |
92 | 93 |
94 |
95 | 96 | 97 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /browserUI/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Recursive Ordinals 7 | 8 | 9 | 10 | 38 | 39 | 133 | 134 | 135 | 136 | 137 |
138 | 139 |

Compress your code and use on-chain libraries

140 | 141 |
142 |

Select Libraries

143 | 144 |
145 | 146 | 188 | 189 | 190 |
191 | 192 |
193 | 194 | 195 |
196 |
197 | 198 |
199 |

Compress Text

200 |
201 | 202 |
203 | 204 |
205 |

Compress Files

206 |
207 | 208 |
209 |
210 | 211 | 232 | 233 | 234 | 237 | 238 | 344 | 345 | 346 |
347 |
348 |
349 | 354 |
355 |
356 |
357 | 358 | 359 |
360 | 361 | 362 | 363 | 364 | 365 | -------------------------------------------------------------------------------- /compress-html/examples/7345219 Space Shooter compressed.html: -------------------------------------------------------------------------------- 1 |
21 | 22 | --------------------------------------------------------------------------------