1 | ## Experimenting with Cuneiform
|
2 |
|
3 | I really like the look and technical design of [Neo-Assyrian cuneiform](https://en.wikipedia.org/wiki/Cuneiform_script#Assyrian_cuneiform), and because my software and company are oriented around creating permanent technical documentation that will stand the test of time, and because I've adopted the *clay* metaphor in my software, it seemed like a good idea to use cuneiform to try to develop a logo.
|
4 |
|
5 | I'm not an artist and can barely handle a pencil, but I can write code. So I studied the basic elements of the glyphs and broke them down into a single *stalk* element, which can be parametrized to achieve all of the possibilities in Neo-Assyrian. Note that the earlier cuneiforms are not as amenable to this, because they had yet to be standardized and mechanized.
|
6 |
|
7 | One of my favorite glyphs is `KIR7 (NIM× NÍG.KÁR)` (TBD add good link and definition), which shows different examples of stalks composited together to form a figure:
|
8 |
|
9 | ![](/resources/KIR7_NIM_NIG_KAR_.png)
|
10 |
|
11 | ### Work-in-progress
|
12 |
|
13 | This is a work-in-progress that may eventually become a separate blog post. Right now, I'm trying to unify all three of the diagrams to use a common definition of my `stalk` function. However, each of the diagrams originally used a custom `stalk` function with slightly different internal parameters, including the arc-depth for the arc at the bottom of the stalk. I need to improve `stalk` to make this parameter explicit so that each of the diagrams can have its appropriate curvature.
|
14 |
|
15 | ### Reusable `stalk` definition
|
16 |
|
17 | Example of a reusable function, `stalk`, which can be used by subsequent playables. Note the `p5` initial parameter, which must be replaced with the per-playable (sketch) instance of `p5`, by using the construct:
|
18 |
|
19 | ```javascript
|
20 | const stalk = window.stalk.bind(this, p5);
|
21 | ```
|
22 |
|
23 | I've set this `stalk` definition to `/autoplay` to ensure it executes before the other, optionally playable content.
|
24 |
|
25 | ---
|
26 |
|
27 |
|
28 | ```javascript/autoplay/playable
|
29 | function stalk(p5, arrowTailX, arrowTailY, arrowWidth, arrowHeight, stalkWidth, stalkHeight, angle, fillColor, bgColor) {
|
30 | // console.log('stalk1', window.p5, this.p5, p5, this, arguments, arrowTailX, arrowTailY, arrowWidth, arrowHeight, stalkWidth, stalkHeight, angle, fillColor, bgColor);
|
31 |
|
32 | p5.push();
|
33 | var tx = arrowTailX;
|
34 | var ty = arrowTailY;
|
35 | // p5.fill(bgColor);
|
36 | p5.translate(tx, ty);
|
37 | p5.rotate(angle);
|
38 |
|
39 | arrowTailX -= tx;
|
40 | arrowTailY -= ty;
|
41 | var halfWidth = arrowWidth / 2;
|
42 | var thirdWidth = arrowWidth / 3;
|
43 | var quarterWidth = arrowWidth / 4;
|
44 | var threeQuarterWidth = 3 * arrowWidth / 4;
|
45 |
|
46 | p5.noStroke();
|
47 | p5.fill(fillColor);
|
48 | p5.triangle(arrowTailX - arrowHeight, arrowTailY, arrowTailX + arrowHeight, arrowTailY, arrowTailX, arrowTailY + arrowHeight);
|
49 |
|
50 | p5.fill(fillColor);
|
51 | p5.rect(arrowTailX - stalkWidth / 2, arrowTailY, stalkWidth, stalkHeight + arrowWidth / 4);
|
52 |
|
53 | p5.fill(bgColor);
|
54 |
|
55 | arrowWidth += arrowWidth * 0.35;
|
56 | arrowTailY -= arrowHeight * 0.2;
|
57 |
|
58 | p5.noStroke();
|
59 | // p5.strokeWeight(2);
|
60 | // p5.stroke('yellowgreen');
|
61 | p5.arc(
|
62 | arrowTailX,
|
63 | arrowTailY,
|
64 | arrowWidth,
|
65 | arrowHeight,
|
66 | 0 + p5.PI * 0,
|
67 | p5.PI - p5.PI * 0,
|
68 | p5.CHORD);
|
69 |
|
70 | p5.pop();
|
71 | }
|
72 | window.stalk = stalk;
|
73 | ```
|
74 |
|
75 |
|
76 |
|
77 | ### Trying to replicate Neo-Assyrian Cuneiform
|
78 |
|
79 | ```p5js/playable/autoplay
|
80 |
|
81 | var stalk = null;
|
82 |
|
83 | const ksimImage = p5.loadImage('resources/KSIMGlyph.png');
|
84 | const sirImage = p5.loadImage('resources/SIRGlyph.png');
|
85 | const bgColor = 'white';
|
86 |
|
87 | function drawQ() {
|
88 | var centerX = p5.width / 2;
|
89 | var centerY = p5.height / 2;
|
90 | var stalkRadius = 100;
|
91 | var stalkDiameter = 2 * stalkRadius;
|
92 | p5.push();
|
93 | p5.strokeWeight(10);
|
94 | p5.stroke('darkslateblue');
|
95 | p5.fill('aliceblue');
|
96 | p5.ellipse(centerX, centerY, stalkDiameter, stalkDiameter);
|
97 | p5.pop();
|
98 |
|
99 | var arrowWidth = 40;
|
100 | var arrowHeight = 15;
|
101 | var stalkWidth = 6;
|
102 | var stalkHeight = 60;
|
103 | var stalkStagger = 0;
|
104 | var numSectors = 10;
|
105 | var sectorSize = p5.TWO_PI / numSectors;
|
106 |
|
107 | for (var i = 0; i < numSectors; ++i) {
|
108 | var fillColor = 254 * i / numSectors;
|
109 | var rotationAngle = sectorSize * i;
|
110 | var stalkDeltaX = p5.cos(rotationAngle) * stalkRadius;
|
111 | var stalkDeltaY = p5.sin(rotationAngle) * stalkRadius;
|
112 | stalk(centerX + stalkDeltaX,
|
113 | centerY + stalkDeltaY,
|
114 | arrowWidth,
|
115 | arrowHeight,
|
116 | stalkWidth,
|
117 | stalkHeight,
|
118 | rotationAngle + sectorSize,
|
119 | fillColor,
|
120 | bgColor);
|
121 | }
|
122 | }
|
123 |
|
124 | p5.windowResized = function() {
|
125 | p5.resizeCanvas(p5.windowWidth - 70, 400);
|
126 | };
|
127 |
|
128 | p5.setup = function() {
|
129 | stalk = window.stalk.bind(this, p5);
|
130 | p5.createCanvas(100, 100);
|
131 | p5.windowResized();
|
132 | p5.background('aliceblue');
|
133 | p5.noStroke();
|
134 | };
|
135 |
|
136 | p5.draw = function() {
|
137 | drawQ();
|
138 | p5.fill(0);
|
139 | p5.image(ksimImage, 10, 0, 100, 100);
|
140 | p5.text('KSIM', 30, 100);
|
141 | p5.image(sirImage, p5.width - 150, 0, 100, 100);
|
142 | p5.text('ŜIR', p5.width - 100, 100);
|
143 | p5.frameRate(1);
|
144 | };
|
145 | ```
|
146 |
|
147 |
|
148 |
|
149 | ## InfoClay Logo
|
150 |
|
151 | ```p5js/playable/autoplay
|
152 |
|
153 | const bgColor = 'aliceblue';
|
154 | var stalk = null;
|
155 |
|
156 | function drawQ() {
|
157 | var centerX = p5.width / 2;
|
158 | var centerY = p5.height / 2;
|
159 | var stalkRadius = 100;
|
160 | var stalkDiameter = 2 * stalkRadius;
|
161 | var circleDiameter = stalkDiameter + 45;
|
162 | p5.push();
|
163 | p5.strokeWeight(8);
|
164 | p5.stroke('yellowgreen');
|
165 | p5.fill('aliceblue');
|
166 | p5.ellipse(centerX, centerY, circleDiameter, circleDiameter);
|
167 | p5.pop();
|
168 | p5.fill('royalblue');
|
169 | p5.textFont('xkcd');
|
170 | p5.textSize(144);
|
171 | p5.text('I', centerX - 60, centerY + 45);
|
172 | p5.textSize(120);
|
173 | p5.text('C', centerX + 5, centerY + 30);
|
174 | var arrowWidth = 45;
|
175 | var arrowHeight = 25;
|
176 | var stalkWidth = 10;
|
177 | var stalkHeight = 35;
|
178 | var numSectors = 8;
|
179 | var sectorSize = p5.TWO_PI / numSectors;
|
180 |
|
181 | for (var i = 0; i < numSectors; ++i) {
|
182 | var fillColor = 254 * (i + 1) / numSectors;
|
183 | var rotationAngle = sectorSize * i;
|
184 | var stalkDeltaX = p5.cos(rotationAngle) * stalkRadius;
|
185 | var stalkDeltaY = p5.sin(rotationAngle) * stalkRadius;
|
186 | stalk(centerX + stalkDeltaX,
|
187 | centerY + stalkDeltaY,
|
188 | arrowWidth,
|
189 | arrowHeight,
|
190 | stalkWidth,
|
191 | stalkHeight,
|
192 | rotationAngle + sectorSize,
|
193 | fillColor,
|
194 | bgColor);
|
195 | }
|
196 | }
|
197 |
|
198 |
|
199 | p5.windowResized = function() {
|
200 | p5.resizeCanvas(p5.windowWidth - 70, 300);
|
201 | };
|
202 |
|
203 | p5.setup = function() {
|
204 | stalk = window.stalk.bind(this, p5);
|
205 |
|
206 | p5.createCanvas(100, 100);
|
207 | p5.windowResized();
|
208 |
|
209 | p5.noStroke();
|
210 | };
|
211 |
|
212 | p5.draw = function() {
|
213 | drawQ();
|
214 | p5.fill(0);
|
215 | p5.frameRate(1);
|
216 | };
|
217 | ```
|
218 |
|
219 |
|
220 | ### Quantum Clay Logo
|
221 |
|
222 |
|
223 | ```p5js/playable/autoplay
|
224 | var stalk = null;
|
225 |
|
226 | var bgColor = '#400';
|
227 |
|
228 | function drawRing(sectorSkew, numSectors, centerX, centerY, qMode, cMode) {
|
229 | var stalkRadius = 70;
|
230 | var stalkDiameter = 2 * stalkRadius;
|
231 |
|
232 | var arrowHeight = 40;
|
233 | var arrowWidth = 60;
|
234 | var stalkWidth = 10;
|
235 | var stalkHeight = 5;
|
236 | var stalkStagger = 0;
|
237 | var sectorSize = p5.TWO_PI / numSectors;
|
238 |
|
239 | for (var i = 0; i < numSectors; ++i) {
|
240 | var fillColor = (254 * (i + 1) / numSectors) % 254;
|
241 | fillColor = p5.color(
|
242 | 120,
|
243 | 50 + 200 * ((i + 0) % numSectors) / numSectors,
|
244 | 200 + 50 * ((i + 0) % numSectors) / numSectors);
|
245 | var rotationAngle = sectorSize * i + sectorSkew;
|
246 | var stalkDeltaX = p5.cos(p5.HALF_PI + rotationAngle) * stalkRadius;
|
247 | var stalkDeltaY = p5.sin(p5.HALF_PI + rotationAngle) * stalkRadius;
|
248 | var stalkWidthOverride = stalkWidth;
|
249 | var stalkHeightOverride = stalkHeight;
|
250 | if (qMode && (i === (numSectors - 1))) {
|
251 | stalkWidthOverride = 4 * stalkWidth;
|
252 | stalkHeightOverride = 1.0 * arrowHeight;
|
253 | }
|
254 | if (cMode && (i === 2)) {
|
255 | // stalkWidthOverride = 2 * stalkWidth;
|
256 | // stalkHeightOverride = 2 * arrowHeight;
|
257 | }
|
258 | if (cMode && ((i > 4) && (i < 6))) {
|
259 | continue;
|
260 | }
|
261 | stalk(centerX + stalkDeltaX,
|
262 | centerY + stalkDeltaY,
|
263 | arrowWidth,
|
264 | arrowHeight,
|
265 | stalkWidthOverride,
|
266 | stalkHeightOverride,
|
267 | rotationAngle,
|
268 | fillColor,
|
269 | bgColor);
|
270 | }
|
271 | }
|
272 |
|
273 | function drawQ() {
|
274 | drawRing(0, 6, p5.width * 0.3, p5.height * 0.375, true, false);
|
275 | }
|
276 |
|
277 | function drawC() {
|
278 | var skew = -0.165 * p5.PI;
|
279 | drawRing(skew, 6, p5.width * 0.748, p5.height * 0.635, false, true);
|
280 | }
|
281 |
|
282 | function drawBox() {
|
283 | var margin = 1;
|
284 | var arrowWidth = 60;
|
285 | var arrowHeight = arrowWidth / 2;
|
286 | var stalkWidth = 10;
|
287 | var fillColor = 'royalblue';
|
288 | // p5.background('lightyellow');
|
289 | // p5.fill('orange');
|
290 | // p5.stroke('green');
|
291 |
|
292 | stalk(margin + arrowWidth / 2,
|
293 | p5.height - (margin + arrowWidth / 2),
|
294 | arrowWidth,
|
295 | arrowHeight,
|
296 | stalkWidth,
|
297 | p5.height * 0.4 - 2 * (margin + arrowWidth),
|
298 | p5.PI,
|
299 | fillColor,
|
300 | bgColor);
|
301 | stalk(p5.width - (margin + arrowWidth / 2),
|
302 | margin + arrowWidth / 2,
|
303 | arrowWidth,
|
304 | arrowHeight,
|
305 | stalkWidth,
|
306 | p5.height * 0.4 - 2 * (margin + arrowWidth),
|
307 | 0,
|
308 | fillColor,
|
309 | bgColor);
|
310 | stalk(p5.width * 0.4 + margin + arrowWidth / 2,
|
311 | margin + arrowWidth / 2,
|
312 | arrowWidth,
|
313 | arrowHeight,
|
314 | stalkWidth,
|
315 | p5.width * 0.6 - 2 * (margin + arrowWidth),
|
316 | p5.PI + p5.HALF_PI,
|
317 | fillColor,
|
318 | bgColor);
|
319 | stalk(p5.width * 0.6 - (margin + arrowWidth / 2),
|
320 | p5.height - (margin + arrowWidth / 2),
|
321 | arrowWidth,
|
322 | arrowHeight,
|
323 | stalkWidth,
|
324 | p5.width * 0.6 - 2 * (margin + arrowWidth),
|
325 | p5.HALF_PI,
|
326 | fillColor,
|
327 | bgColor);
|
328 | }
|
329 |
|
330 | p5.setup = function() {
|
331 | stalk = window.stalk.bind(this, p5);
|
332 |
|
333 | p5.createCanvas(500, 500);
|
334 | p5.background(bgColor);
|
335 | p5.noStroke();
|
336 | };
|
337 |
|
338 | p5.draw = function() {
|
339 | drawQ();
|
340 | drawC();
|
341 | drawBox();
|
342 | p5.frameRate(1);
|
343 | };
|
344 | ```
|
345 |
|
346 | ---
|
347 |
|
348 | [Back to Home](:@Home)
|
349 |
|