├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── favicon.ico
├── fractals.css
├── fractals.js
├── img
├── css-houdini-fractals.png
├── favicon.sketch
├── fractals-1.png
├── fractals-2.png
└── fractals-3.png
├── index.html
├── package.json
└── server.js
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Binary Files
5 | *.sketch binary
6 | *.ico binary
7 | *.png binary
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Files
2 | .DS_Store
3 | Desktop.ini
4 | Thumbs.db
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12 | HEREUNDER.
13 |
14 | Statement of Purpose
15 |
16 | The laws of most jurisdictions throughout the world automatically confer
17 | exclusive Copyright and Related Rights (defined below) upon the creator
18 | and subsequent owner(s) (each and all, an "owner") of an original work of
19 | authorship and/or a database (each, a "Work").
20 |
21 | Certain owners wish to permanently relinquish those rights to a Work for
22 | the purpose of contributing to a commons of creative, cultural and
23 | scientific works ("Commons") that the public can reliably and without fear
24 | of later claims of infringement build upon, modify, incorporate in other
25 | works, reuse and redistribute as freely as possible in any form whatsoever
26 | and for any purposes, including without limitation commercial purposes.
27 | These owners may contribute to the Commons to promote the ideal of a free
28 | culture and the further production of creative, cultural and scientific
29 | works, or to gain reputation or greater distribution for their Work in
30 | part through the use and efforts of others.
31 |
32 | For these and/or other purposes and motivations, and without any
33 | expectation of additional consideration or compensation, the person
34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35 | is an owner of Copyright and Related Rights in the Work, voluntarily
36 | elects to apply CC0 to the Work and publicly distribute the Work under its
37 | terms, with knowledge of his or her Copyright and Related Rights in the
38 | Work and the meaning and intended legal effect of CC0 on those rights.
39 |
40 | 1. Copyright and Related Rights. A Work made available under CC0 may be
41 | protected by copyright and related or neighboring rights ("Copyright and
42 | Related Rights"). Copyright and Related Rights include, but are not
43 | limited to, the following:
44 |
45 | i. the right to reproduce, adapt, distribute, perform, display,
46 | communicate, and translate a Work;
47 | ii. moral rights retained by the original author(s) and/or performer(s);
48 | iii. publicity and privacy rights pertaining to a person's image or
49 | likeness depicted in a Work;
50 | iv. rights protecting against unfair competition in regards to a Work,
51 | subject to the limitations in paragraph 4(a), below;
52 | v. rights protecting the extraction, dissemination, use and reuse of data
53 | in a Work;
54 | vi. database rights (such as those arising under Directive 96/9/EC of the
55 | European Parliament and of the Council of 11 March 1996 on the legal
56 | protection of databases, and under any national implementation
57 | thereof, including any amended or successor version of such
58 | directive); and
59 | vii. other similar, equivalent or corresponding rights throughout the
60 | world based on applicable law or treaty, and any national
61 | implementations thereof.
62 |
63 | 2. Waiver. To the greatest extent permitted by, but not in contravention
64 | of, applicable law, Affirmer hereby overtly, fully, permanently,
65 | irrevocably and unconditionally waives, abandons, and surrenders all of
66 | Affirmer's Copyright and Related Rights and associated claims and causes
67 | of action, whether now known or unknown (including existing as well as
68 | future claims and causes of action), in the Work (i) in all territories
69 | worldwide, (ii) for the maximum duration provided by applicable law or
70 | treaty (including future time extensions), (iii) in any current or future
71 | medium and for any number of copies, and (iv) for any purpose whatsoever,
72 | including without limitation commercial, advertising or promotional
73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74 | member of the public at large and to the detriment of Affirmer's heirs and
75 | successors, fully intending that such Waiver shall not be subject to
76 | revocation, rescission, cancellation, termination, or any other legal or
77 | equitable action to disrupt the quiet enjoyment of the Work by the public
78 | as contemplated by Affirmer's express Statement of Purpose.
79 |
80 | 3. Public License Fallback. Should any part of the Waiver for any reason
81 | be judged legally invalid or ineffective under applicable law, then the
82 | Waiver shall be preserved to the maximum extent permitted taking into
83 | account Affirmer's express Statement of Purpose. In addition, to the
84 | extent the Waiver is so judged Affirmer hereby grants to each affected
85 | person a royalty-free, non transferable, non sublicensable, non exclusive,
86 | irrevocable and unconditional license to exercise Affirmer's Copyright and
87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
88 | maximum duration provided by applicable law or treaty (including future
89 | time extensions), (iii) in any current or future medium and for any number
90 | of copies, and (iv) for any purpose whatsoever, including without
91 | limitation commercial, advertising or promotional purposes (the
92 | "License"). The License shall be deemed effective as of the date CC0 was
93 | applied by Affirmer to the Work. Should any part of the License for any
94 | reason be judged legally invalid or ineffective under applicable law, such
95 | partial invalidity or ineffectiveness shall not invalidate the remainder
96 | of the License, and in such case Affirmer hereby affirms that he or she
97 | will not (i) exercise any of his or her remaining Copyright and Related
98 | Rights in the Work or (ii) assert any associated claims and causes of
99 | action with respect to the Work, in either case contrary to Affirmer's
100 | express Statement of Purpose.
101 |
102 | 4. Limitations and Disclaimers.
103 |
104 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
105 | surrendered, licensed or otherwise affected by this document.
106 | b. Affirmer offers the Work as-is and makes no representations or
107 | warranties of any kind concerning the Work, express, implied,
108 | statutory or otherwise, including without limitation warranties of
109 | title, merchantability, fitness for a particular purpose, non
110 | infringement, or the absence of latent or other defects, accuracy, or
111 | the present or absence of errors, whether or not discoverable, all to
112 | the greatest extent permissible under applicable law.
113 | c. Affirmer disclaims responsibility for clearing rights of other persons
114 | that may apply to the Work or any use thereof, including without
115 | limitation any person's Copyright and Related Rights in the Work.
116 | Further, Affirmer disclaims responsibility for obtaining any necessary
117 | consents, permissions or other rights required for any use of the
118 | Work.
119 | d. Affirmer understands and acknowledges that Creative Commons is not a
120 | party to this document and has no duty or obligation with respect to
121 | this CC0 or use of the Work.
122 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CSS Houdini Fractals
2 |
3 | Drawing Fractals with CSS Houdini.
4 |
5 | This demo was created for https://github.com/GoogleChromeLabs/houdini.how and can be also previewed on the main Chrome Labs site https://houdini.how/
6 |
7 | **From:** https://developer.mozilla.org/en-US/docs/Web/Houdini
8 | > Houdini is a set of low-level APIs that exposes parts of the CSS engine, giving developers the power to extend CSS by hooking into the styling and layout process of a browser’s rendering engine.
9 |
10 | ## 🌐 Try it online!
11 |
12 | https://conradsollitt.github.io/css-houdini-fractals/
13 |
14 | ## 🚀 Download locally
15 |
16 | This repository has zero dependencies. Only the [fractals.js](fractals.js) file is required to use it with any site. If you would like to try the demo locally download this repository and follow the commands below.
17 |
18 | ```bash
19 | # If you have node installed:
20 | npm start
21 |
22 | # If you do not have node installed and have Python installed then depending on
23 | # the version Python and OS installed one of the following commands should work:
24 | python3 -m http.server
25 | python -m http.server
26 | python -m SimpleHTTPServer
27 | ```
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | ## 💡 Usage
38 |
39 | ### Use CSS Houdini API to import the [fractals.js](fractals.js) file
40 |
41 | ```js
42 | // Modern Browsers - Import JavaScript file from CDN
43 | if ('paintWorklet' in CSS) {
44 | CSS.paintWorklet.addModule('https://unpkg.com/css-houdini-fractals@1.1.0/fractals.js');
45 | }
46 |
47 | // Modern Browsers - Using Local build, only a single file is needed
48 | if ('paintWorklet' in CSS) {
49 | CSS.paintWorklet.addModule('fractals.js');
50 | }
51 | ```
52 |
53 | ### Use the [css-paint-polyfill] Polyfill to support all Modern Browsers (won't work with IE)
54 |
55 | https://github.com/GoogleChromeLabs/css-paint-polyfill
56 |
57 | ```html
58 |
66 | ```
67 |
68 | ### HTML
69 |
70 | The type of HTML element and class name does not matter, rather height and width are needed.
71 |
72 | ```html
73 |
76 |
77 |
78 | ```
79 |
80 | ### CSS Options
81 |
82 | ```css
83 | /*
84 | By default only `background-image: paint(fractals)` is needed.
85 | */
86 | .fractals {
87 | background-image: paint(fractals);
88 | }
89 |
90 | /*
91 | The example below shows all options with default values, except
92 | for [--colors] which is empty resulting in black lines.
93 |
94 | [--colors] are dynamic and based on the number of colors included.
95 | The delimiter for [--colors] is a space so these examples are all valid:
96 | --colors: red green blue;
97 | --colors: black;
98 | --colors: #000 #222 #444 #666 #888 #aaa #ccc;
99 |
100 | [--shape] = One of [line, circle, square]
101 | [--debug-to-console] and [-show-origin] = 0 or 1
102 | */
103 | .fractals {
104 | --colors: red green blue cyan magenta yellow;
105 | --angle: 30;
106 | --starting-length-percent: 22;
107 | --next-line-size: 0.8;
108 | --shape: line;
109 | --max-draw-count: 10000;
110 | --debug-to-console: 0;
111 | --show-origin: 0;
112 | background-image: paint(fractals);
113 | }
114 | ```
115 |
116 | ## 🎨 CSS Houdini Links
117 |
118 | * https://houdini.how/
119 | * https://github.com/GoogleChromeLabs/houdini.how
120 | * https://developer.mozilla.org/en-US/docs/Web/Houdini
121 |
122 | ## ❄️ Fractals
123 |
124 | * https://fractalfoundation.org/resources/what-are-fractals/
125 | * https://en.wikipedia.org/wiki/Fractal
126 | * https://mathworld.wolfram.com/Fractal.html
127 | * https://www.wired.com/2010/09/fractal-patterns-in-nature/
128 |
129 | ## 🌐 Additional JavaScript Fractal Links
130 | * https://thefractal.zone/
131 | * https://github.com/delimitry/fractals-js
132 | * https://progur.com/2017/02/create-mandelbrot-fractal-javascript.html
133 | * https://medium.com/@yortuc/fractal-fun-with-javascript-2102d03ad22b
134 | * https://progur.com/2016/10/procedural-generation-create-fractal-trees-javascript.html
135 | * https://lautarolobo.xyz/blog/use-javascript-and-html5-to-code-a-fractal-tree/
136 | * https://www.lesscake.com/fractals-chaos-game
137 | * https://repl.it/talk/learn/Julia-Fractals-in-JavaScript/12806
138 | * http://rectangleworld.com/blog/archives/462
139 | * http://slicker.me/fractals/animate.htm
140 |
141 | ## 📝 License
142 |
143 | [](https://creativecommons.org/publicdomain/zero/1.0/)
144 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConradSollitt/css-houdini-fractals/7361fca9b05a112a02f747f01af30b24dc46ff98/favicon.ico
--------------------------------------------------------------------------------
/fractals.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | height: 100%;
3 | }
4 |
5 | html {
6 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
7 | }
8 |
9 | body {
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | background-image: linear-gradient(180deg, hsl(0 0% 100% / 0.2) 1%, hsl(0 0% 100% / 0.2) 30%,#fff),
14 | linear-gradient(25deg, #ce084b, #017bdc 32%,#FFEB3B);
15 | background-repeat: no-repeat;
16 | background-size: cover;
17 | }
18 |
19 | h1,
20 | section {
21 | padding: 20px;
22 | margin: 20px;
23 | background-color: white;
24 | box-shadow: 0 1px 2px rgba(0,0,0,.5);
25 | }
26 | section { max-width: calc(100vw - 80px); }
27 |
28 | /*
29 | For more on how the
works see my personal site and the CSS source:
30 | https://conradsollitt.com/
31 | */
32 | h1 { font-size:3em; letter-spacing: 0.08em; text-align: center; }
33 | h1 span { --h: 0; --s: 100%; --l: 50%; }
34 | h1 span:nth-child(2n) { --h: 120; }
35 | h1 span:nth-child(3n) { --h: 240; }
36 | h1 span:nth-child(4n) { --h: 60; }
37 | h1 span {
38 | color: hsl(var(--h), var(--s), var(--l));
39 | --darkest: calc(var(--l) - 30%);
40 | --outline: hsl(var(--h), var(--s), var(--darkest));
41 | text-shadow:
42 | -1px -1px var(--outline),
43 | 1px -1px var(--outline),
44 | -1px 1px var(--outline),
45 | 1px 1px var(--outline);
46 | }
47 |
48 | .flex { display:flex; flex-wrap: wrap; justify-content: center; }
49 | .center { justify-content: center; }
50 |
51 | section > div {
52 | display: flex;
53 | padding: 10px;
54 | flex-direction: column;
55 | }
56 | label {
57 | margin-bottom: 8px;
58 | width:150px;
59 | color: #888;
60 | }
61 | select,
62 | input[type="text"],
63 | input[type="number"] { padding:.5em 1em; }
64 | input { position: relative; }
65 | input::before {
66 | position: absolute;
67 | content: attr(current-value);
68 | top: -25px;
69 | right: 0;
70 | font-weight: bold;
71 | font-size: 1.2em;
72 | color: black;
73 | }
74 | @media (min-width: 800px) {
75 | section > div { flex-direction: row; justify-content: space-between; }
76 | label { margin-bottom: 0; margin-right: 60px; }
77 | input[type="range"] { width: 200px; }
78 | input::before { left: -40px; right: initial; top: initial; }
79 | input#max-draw-count::before { left: -60px; }
80 | }
81 |
82 | .demo {
83 | width: calc(100vw - 80px);
84 | height: 50vh;
85 | }
86 | @media (min-width: 800px) {
87 | .demo { width:600px; }
88 | }
89 | @media (min-width: 1200px) {
90 | .demo { width:50vw; }
91 | }
92 |
93 | a[href^="https://github.com/"] {
94 | display: flex;
95 | align-items: center;
96 | justify-content: space-between;
97 | margin-top: 2em;
98 | }
99 | a[href^="https://github.com/"]::before {
100 | content: '';
101 | background-image: url(https://github.githubassets.com/favicons/favicon.svg);
102 | background-repeat: no-repeat;
103 | height: 32px;
104 | width: 32px;
105 | padding-right: 2em;
106 | }
107 |
108 | /*
109 | By default only `background-image: paint(fractals)` is needed.
110 |
111 | The example below shows all options with default values, except
112 | for [--colors] which is empty resulting in black lines.
113 |
114 | [--colors] are dynamic and based on the number of colors included.
115 | [--shape] = One of [line, circle, square]
116 | [--debug-to-console] and [-show-origin] = 0 or 1
117 | */
118 | .fractals {
119 | --colors: red green blue cyan magenta yellow;
120 | --angle: 30;
121 | --starting-length-percent: 22;
122 | --next-line-size: 0.8;
123 | --shape: line;
124 | --max-draw-count: 10000;
125 | --debug-to-console: 0;
126 | --show-origin: 0;
127 | background-image: paint(fractals);
128 | }
129 |
--------------------------------------------------------------------------------
/fractals.js:
--------------------------------------------------------------------------------
1 | /* global registerPaint */
2 | /* jshint esversion:6 */
3 |
4 | /**
5 | * Fractal Drawing with CSS Houdini
6 | *
7 | * @link https://houdini.how/
8 | * @link https://github.com/GoogleChromeLabs/houdini.how
9 | * @link https://developer.mozilla.org/en-US/docs/Web/Houdini
10 | * @link https://fractalfoundation.org/resources/what-are-fractals/
11 | * @link https://en.wikipedia.org/wiki/
12 | * @link https://mathworld.wolfram.com/Fractal.html
13 | * @link https://www.wired.com/2010/09/fractal-patterns-in-nature/
14 | * @author Conrad Sollitt (https://conradsollitt.com)
15 | * @license CC0 "Public Domain" license
16 | */
17 | class Fractals {
18 | /**
19 | * Required Houdini API for Custom Properties.
20 | * If a variable is not included then `props.get(name)` will
21 | * return `null` from the `paint()` function.
22 | */
23 | static get inputProperties() {
24 | return [
25 | '--colors',
26 | '--angle',
27 | '--starting-length-percent',
28 | '--next-line-size',
29 | '--shape',
30 | '--max-draw-count',
31 | '--debug-to-console',
32 | '--show-origin',
33 | ];
34 | }
35 |
36 | /**
37 | * Houdini API
38 | *
39 | * @param {PaintRenderingContext2D} ctx
40 | * @param {object} size
41 | * @param {object} props
42 | */
43 | paint(ctx, size, props) {
44 | // Optional debug options
45 | const debugToConsole = (props.get('--debug-to-console').toString().trim() === '1');
46 | let startDate;
47 | if (debugToConsole) {
48 | startDate = new Date();
49 | console.log('-'.repeat(80));
50 | console.log(`Starting CSS [paint(fractals)] at: ${startDate.toLocaleTimeString()}`);
51 | console.log(size);
52 | console.log(props);
53 | }
54 | this.showOrigin = (props.get('--show-origin').toString().trim() === '1');
55 |
56 | // Default angle to 30%
57 | this.angle = parseInt(props.get('--angle'), 10) || 30;
58 |
59 | // Starting Line Length - Default to 22 %
60 | let startingLengthPct = parseInt(props.get('--starting-length-percent'), 10);
61 | if (isNaN(startingLengthPct) || startingLengthPct < 5 || startingLengthPct > 95) {
62 | startingLengthPct = 22;
63 | }
64 | const length = (size.height / (100 / startingLengthPct));
65 |
66 | // Next line size - defaults to 0.8 for 80%
67 | this.nextLineSize = parseFloat(props.get('--next-line-size'));
68 | if (isNaN(this.nextLineSize) || this.nextLineSize < 0.1 || this.nextLineSize > 0.9) {
69 | this.nextLineSize = 0.8;
70 | }
71 |
72 | // For safety due to recursive function or by design if the number
73 | // is small only half (give or take) the the drawing will render.
74 | // If [--max-draw-count] is reached the number of shapes will be
75 | // slightly lager than the max draw count due to recursive functions
76 | // that need to finish running.
77 | this.maxDrawCount = parseInt(props.get('--max-draw-count'), 10) || 10000;
78 | this.drawCount = 0;
79 |
80 | // Colors are space delimited
81 | this.colors = props.get('--colors').toString().trim().split(' ').map(s => s.trim());
82 | this.colorCount = this.colors.length;
83 |
84 | // Function for type Shape to Draw - Defaults to line.
85 | let shape;
86 | const x = (size.width / 2);
87 | const y = size.height - (this.showOrigin ? 4 : 0);
88 | switch (props.get('--shape').toString().trim()) {
89 | case 'circle':
90 | shape = (ctx, diameter) => {
91 | const radius = (diameter / 2);
92 | ctx.arc(0, -radius, radius, 0, Math.PI * 2, true);
93 | };
94 | break;
95 | case 'square':
96 | shape = (ctx, length) => {
97 | // Typically when using canvas a square would be drawn using
98 | // `rect()`, however due to the rotated origin each line of
99 | // the square must be drawn to match the layout of other shapes.
100 | // ctx.rect(x, y, length, length);
101 | const half_len = length / 2;
102 | ctx.moveTo(0, 0);
103 | ctx.lineTo(half_len, 0);
104 | ctx.lineTo(half_len, -length);
105 | ctx.lineTo(0, -length);
106 | ctx.lineTo(-half_len, -length);
107 | ctx.lineTo(-half_len, 0);
108 | ctx.lineTo(0, 0);
109 | };
110 | break;
111 | default: // 'line'
112 | shape = (ctx, length) => {
113 | ctx.moveTo(0, 0);
114 | ctx.lineTo(0, -length);
115 | };
116 | }
117 |
118 | // Start call to recursive `draw()`
119 | this.draw(ctx, shape, x, y, length, 0, 0);
120 | if (debugToConsole) {
121 | const endDate = new Date();
122 | const duration = endDate.getTime() - startDate.getTime();
123 | console.log(`Finished CSS [paint(fractals)] at: ${startDate.toLocaleTimeString()}`);
124 | console.log(`Duration in milliseconds: ${duration}`);
125 | console.log(`Function calls: ${this.drawCount}`);
126 | }
127 | }
128 |
129 | /**
130 | * Recursive function that draws the fractals
131 | *
132 | * @param {PaintRenderingContext2D} ctx
133 | * @param {function} shape
134 | * @param {number} x
135 | * @param {number} y
136 | * @param {number} length
137 | * @param {number} angle
138 | */
139 | draw(ctx, shape, x, y, length, angle) {
140 | // Draw Shape
141 | ctx.beginPath();
142 | ctx.save();
143 | ctx.translate(x, y);
144 | ctx.rotate(angle * Math.PI / 180);
145 | if (this.colorCount > 0) {
146 | const colorIndex = this.drawCount % this.colorCount;
147 | ctx.strokeStyle = this.colors[colorIndex];
148 | }
149 | shape(ctx, length);
150 | ctx.stroke();
151 |
152 | // This helps with debugging when adding new shapes
153 | if (this.showOrigin) {
154 | ctx.fillStyle = ctx.strokeStyle;
155 | ctx.fillRect(0, 0, 4, 4);
156 | }
157 |
158 | // Exit once the line length becomes too small or
159 | // if the number of max function calls is exceeded.
160 | this.drawCount++;
161 | if (this.drawCount > this.maxDrawCount || length < 10) {
162 | ctx.restore();
163 | return;
164 | }
165 |
166 | // Recursively call this function twice, once for the left side and once for the right side
167 | this.draw(ctx, shape, 0, -length, length * this.nextLineSize, -this.angle);
168 | this.draw(ctx, shape, 0, -length, length * this.nextLineSize, this.angle);
169 | ctx.restore();
170 | }
171 | }
172 |
173 | registerPaint('fractals', Fractals);
174 |
--------------------------------------------------------------------------------
/img/css-houdini-fractals.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConradSollitt/css-houdini-fractals/7361fca9b05a112a02f747f01af30b24dc46ff98/img/css-houdini-fractals.png
--------------------------------------------------------------------------------
/img/favicon.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConradSollitt/css-houdini-fractals/7361fca9b05a112a02f747f01af30b24dc46ff98/img/favicon.sketch
--------------------------------------------------------------------------------
/img/fractals-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConradSollitt/css-houdini-fractals/7361fca9b05a112a02f747f01af30b24dc46ff98/img/fractals-1.png
--------------------------------------------------------------------------------
/img/fractals-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConradSollitt/css-houdini-fractals/7361fca9b05a112a02f747f01af30b24dc46ff98/img/fractals-2.png
--------------------------------------------------------------------------------
/img/fractals-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConradSollitt/css-houdini-fractals/7361fca9b05a112a02f747f01af30b24dc46ff98/img/fractals-3.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | CSS Houdini Fractals Demo
7 |
8 |
9 |
10 |
11 |
68 |
69 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "css-houdini-fractals",
3 | "version": "1.1.0",
4 | "description": "Fractals Drawing with CSS Houdini",
5 | "main": "fractals.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "node server.js"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/ConradSollitt/css-houdini-fractals.git"
13 | },
14 | "keywords": [
15 | "CSS",
16 | "Houdini",
17 | "Fractals"
18 | ],
19 | "author": "Conrad Sollitt (https://conradsollitt.com)",
20 | "license": "CC0-1.0",
21 | "homepage": "https://github.com/ConradSollitt/css-houdini-fractals"
22 | }
23 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Simple Node Web Server for sending static files using using only
3 | * Node.js built-in features without any outside dependencies.
4 | *
5 | * To run:
6 | * npm start
7 | *
8 | * If you do not have node/npm installed and still want to run this
9 | * site locally then you can also run it if you have Python installed.
10 | * Depending on the version Python installed and the OS one of the
11 | * following commands should work:
12 | * python3 -m http.server
13 | * python -m http.server
14 | * python -m SimpleHTTPServer
15 | *
16 | * Important - This script is very minimal by design and includes no error handling.
17 | * It works well but has few features so is not intended for production apps.
18 | *
19 | * Since this file is small you can step through the code using a debugger
20 | * which makes it is useful for learning purposes.
21 | *
22 | * @link https://github.com/dataformsjs/awesome-web-react/blob/master/server.js
23 | * @author Conrad Sollitt (https://conradsollitt.com)
24 | * @license CC0 "Public Domain" license
25 | */
26 |
27 | /* Validates online with both [jshint] and [eslint] */
28 | /* jshint esversion:8, node:true */
29 | /* eslint-env node, es6 */
30 |
31 | 'use strict';
32 |
33 | const http = require('http');
34 | const url = require('url');
35 | const fs = require('fs');
36 | const path = require('path');
37 |
38 | /**
39 | * Allowed mime types
40 | */
41 | const mimeTypes = {
42 | htm: 'text/html; charset=UTF-8',
43 | html: 'text/html; charset=UTF-8',
44 | css: 'text/css',
45 | txt: 'text/plain',
46 | js: 'application/javascript',
47 | jsx: 'application/jsx',
48 | json: 'application/json',
49 | graphql: 'application/graphql',
50 | png: 'image/png',
51 | jpg: 'image/jpeg',
52 | svg: 'image/svg+xml',
53 | ico: 'image/x-icon',
54 | };
55 |
56 | /**
57 | * Simple Web Server for sending Static Files
58 | */
59 | const server = http.createServer((req, res) => {
60 | // Send a 404 Page as an HTML Response
61 | function send404() {
62 | res.statusCode = 404;
63 | res.setHeader('Content-Type', 'text/html; charset=UTF-8');
64 | res.end('
File not found
');
65 | }
66 |
67 | // Send a Response from a File. If the file doesn't exist or the file type is
68 | // not defined in mimeTypes then a 404 HTML Response will be sent to the client.
69 | function sendFile(filePath) {
70 | const data = filePath.split('.');
71 | const fileType = data[data.length-1];
72 | if (mimeTypes[fileType] === undefined) {
73 | send404(); // File type not supported
74 | return;
75 | }
76 | fs.readFile(filePath, (err, content) => {
77 | if (err && err.code === 'ENOENT') {
78 | send404(); // File not found
79 | } else if (err) {
80 | console.error(err);
81 | res.statusCode = 500;
82 | res.end('