tmp/*
log/*
_site
+
+.jekyll-cache
<link rel="manifest" href="/manifest.webmanifest">
<link rel="stylesheet" type="text/css" href="/css/application.css">
+ <script type="module" src="/js/animation.js"></script>
+
<!--
/\
/ O\ U N L I M I T E D
-->
</head>
<body>
- <div class="content-wrapper">
- <header aria-label="Logo">
- <a href="/">Unlimited Pizza</a>
- </header>
- {{ content }}
- </div>
- <div aria-hidden="true" class="tapestry">
- <div class="orangered">
- <div class="red"></div>
- </div>
- <div class="brown">
- <div class="redbrown"></div>
- <div class="lightbrown"></div>
- </div>
- <div class="grey"></div>
- <div class="sand"></div>
- </div>
+ <header aria-label="Logo">
+ <h1>
+ <canvas width=100 height=100></canvas>
+ <a href="/">unlimited.pizza</a>
+ </h1>
+ </header>
+ {{ content }}
</body>
</html>
-/*********************
- * Gontcharova Theme *
- *********************/
-
-body {
- margin: 0;
- background-color: #FFF5E3;
- font-family: Helvetica, Arial, sans-serif;
- display: flex;
- flex-flow: row nowrap;
- transition: all 0.5s ease-in-out;
-}
-
-header {
- margin-top: -20px;
-}
-
-.content-wrapper {
- margin: 100px 0 0 10px;
- width: 45vw;
-}
-
-header a, header a:visited {
- font-family: 'Helvetica Neue', 'Arial Nova', Helvetica, Arial, Freesans, sans-serif;
- font-weight: 100;
- font-size: 96px;
- text-transform: uppercase;
- text-decoration: none;
- color: black;
-}
-
-h1 {
- font-family: 'Bodoni 72', 'Century Schoolbook L', 'Rockwell Nova', serif;
- font-weight: 300;
- font-size: 48px;
-}
-
-ul, p {
- font-size: 16px;
- font-weight: 300;
+h1 canvas {
+ width: 64px;
+ height: 64px;
+ display: inline-block;
+ background-color: gainsboro;
}
ul {
list-style: square;
}
-ul a,
-p a {
- text-transform: lowercase;
- font-weight: 600;
- color: #C7434B;
-}
-
-ul a:visited,
-p a:visited {
- color: #551C22;
-}
-
-ul a:hover,
-p a:hover {
- color: #933B3C;
-}
-
-ul a:active,
-p a:active {
- color: #A9938F;
-}
-
-ul span,
-p span {
- font-style: oblique;
- color: #9E7764;
-}
-
-@media only screen and (max-width: 1024px) {
- header a {
- font-size: 72px;
- }
-}
-
-@media only screen and (max-width: 700px) {
+@media (prefers-color-scheme: dark) {
body {
- flex-flow: column wrap;
- }
-
- header {
- width: 45vw;
- }
-
- .content-wrapper {
- margin: 20px;
- width: auto;
- }
-}
-
-video {
- width: 100%;
-}
-
-/************
- * Tapestry *
- ************/
-
-.orangered { background-color: #C84A0A; }
-.red { background-color: #C7434B; }
-.brown { background-color: #551C22; }
-.redbrown { background-color: #933B3C; }
-.lightbrown { background-color: #9E7764; }
-.grey { background-color: #A9938F; }
-.sand { background-color: #D2BE9A; }
-
-.tapestry {
- order: -1;
-}
-
-.tapestry,
-.tapestry div {
- transition: all 0.5s ease-in-out;
-}
-
-/* Large Tapestry */
-
-.tapestry {
- max-width: 42vw;
- max-height: 42vw;
- display: flex;
- flex-flow: row wrap;
- margin: 100px 0 0 100px;
-}
-
-
-.red {
- width: 14vw;
- height: 14vw;
-}
-
-.red:hover {
- margin: 3.5vw;
- width: 7vw;
- height: 7vw;
-}
-
-.brown,
-.orangered,
-.grey {
- width: 14vw;
- height: 28vw;
-}
-
-.grey:hover {
- width:7vw;
-}
-
-.sand {
- width: 42vw;
- height: 14vw;
-}
-
-.sand:hover {
- height: 2vw;
-}
-
-.redbrown {
- width: 7vw;
- height: 14vw;
-}
-
-.redbrown:hover {
- margin-bottom: 7vw;
-}
-
-.lightbrown {
- width: 7vw;
- height: 7vw;
-}
-
-.lightbrown:hover {
- height: 28vw;
-}
-
-.brown {
- display: flex;
- flex-flow: row wrap;
- align-content: flex-end;
- align-items: flex-end;
-}
-
-@media only screen and (max-width: 1024px) {
- .tapestry {
- max-width: 32vw;
- }
-
- .red {
- width: 32vw;
- height: 4vw;
- }
-
- .red:hover {
- margin: 0;
- width: 64vw;
- height: 16vw;
- }
-
- .orangered {
- width: 16vw;
- height: 20vw;
- }
-
- .brown {
- width: 32vw;
- height: 16vw;
- }
-
- .redbrown {
- width: 16vw;
- height: 16vw;
- position: relative;
- top: -16vw;
- left: 16vw;
- }
-
- .lightbrown {
- width: 8vw;
- height: 8vw;
- }
-
- .grey {
- height: 16vw;
- width: 24vw;
- }
-
- .sand {
- width: 8vw;
- height: 32vw;
- }
-}
-
-@media only screen and (max-width: 700px) {
- .tapestry {
- max-width: 80vw;
- max-height: 8vw;
- margin: 0px;
- flex-flow: column wrap;
- }
-
- .red {
- width: 4vw;
- height: 4vw;
- }
-
- .red:hover {
- width: 24vw;
- height: 24vw;
- }
-
- .orangered {
- width: 16vw;
- height: 8vw;
- }
-
- .brown {
- width: 32vw;
- height: 8vw;
- }
-
- .redbrown {
- width: 24vw;
- height: 4vw;
- position: relative;
- top: 0;
- left: 0;
- }
-
- .lightbrown {
- width: 8vw;
- height: 32vw;
- }
-
- .lightbrown:hover {
- height: 1vw;
- }
-
- .grey {
- height: 4vw;
- width: 38vw;
+ color: white;
+ background-color: black;
}
- .sand {
- width: 8vw;
- height: 32vw;
+ a {
+ color: #5dc1fd;
}
- .sand:hover {
- width: 10vw;
- height: 6vw;
+ a:visited {
+ color: #ed6eff;
}
}
title: /index.html
description: "unlimited.pizza - ruben beltran del río surfs the internet: programming, music, fun times, hugs, bad jokes, and unlimited pizza"
---
-<main title="Projects">
- <h1>Projects.</h1>
-
+<main>
+ <p>The personal website of Rubén Beltrán del Río</p>
+ <p>
+ → <a href="http://blog.unlimited.pizza">blog</a>.
+ </p>
+ <h2>Apps</h2>
<ul>
<li>
<p>
- <a href="http://blog.unlimited.pizza">blog</a>
- <span>(Ongoing)</span>:
- My blog. Only 3 posts at a time.
- <a aria-label="See the source of my blog" href="https://gitlab.com/rbdr/blog">See the source</a>.
- </p>
- </li>
- <li>
- <p>
- <a href="http://do.unlimited.pizza">do</a>
- <span>(Ongoing)</span>:
- A task manager for iOS and MacOS that makes you write your thoughts down when the task is done.
- <a aria-label="See the source of do" href="https://gitlab.com/rbdr/do">See the source</a>.
+ <a href="http://do.unlimited.pizza">do</a>:
+ A task manager for iOS and MacOS that makes you write a journal entry when the task is done.
+ (<a aria-label="See the source of do" href="https://gitlab.com/rbdr/do">source</a>)
</p>
</li>
<li>
<p>
<a href="http://map.unlimited.pizza">map</a>
- <span>(Ongoing)</span>:
A MacOS app that lets you create wardley maps using text.
- <a aria-label="See the source of map" href="https://gitlab.com/rbdr/map">See the source</a>.
+ (<a aria-label="See the source of map" href="https://gitlab.com/rbdr/map">source</a>)
</p>
</li>
+ </ul>
+ <h2>Libraries</h2>
+ <ul>
<li>
<p>
- <a href="https://gitlab.com/serpentity">Serpentity</a>
- <span>(Ongoing)</span>:
+ <a href="https://gitlab.com/serpentity">serpentity</a>:
An entity framework for JavaScript.
</p>
</li>
<li>
<p>
- <a href="https://gitlab.com/rbdr/grafn">grafn</a>
- <span>(Ongoing)</span>:
+ <a href="https://gitlab.com/rbdr/grafn">grafn</a>:
Flow based programming library for javascript.
</p>
</li>
<li>
<p>
- <a href="https://gitlab.com/rbdr/cologne">cologne</a>
- <span>(Ongoing)</span>:
+ <a href="https://gitlab.com/rbdr/cologne">cologne</a>:
Log multiplexer for javascript with no dependencies.
</p>
</li>
+ </ul>
+ <h2>Plugins</h2>
+ <ul>
<li>
<p>
<a href="https://gitlab.com/rbdr/api-notation.vim">API notation for vim</a>,
<a href="https://gitlab.com/rbdr/api-notation-atom">atom</a>, &
<a href="https://gitlab.com/rbdr/api-notation.vscode">vscode</a>, &
- <a href="https://gitlab.com/rbdr/api-notation.tmLanguage">sublime text</a>
- <span>(Ongoing)</span>:
+ <a href="https://gitlab.com/rbdr/api-notation.tmLanguage">sublime text</a>:
A syntax for notating component APIs in a way that's easy to embed in text documents.
</p>
</li>
<li>
<p>
- <a href="https://gitlab.com/rbdr/ngx_http_office_hours_filter_module">Nginx Office Hours</a>
- <span>(2019)</span>:
+ <a href="https://gitlab.com/rbdr/ngx_http_office_hours_filter_module">Nginx Office Hours</a>:
A victory for the server's labor rights: An nginx module that allows you to serve your content only during office hours.
</p>
</li>
+ </ul>
+ <h2>My Things</h2>
+ <ul>
+ <li>
+ <p>
+ <a href="http://myspace.bandcamp.com">music @ bandcamp</a>:
+ Music I've made.
+ </p>
+ </li>
+ <li>
+ <p>
+ <a href="http://soundcloud.com/benbeltran">music @ soundcloud</a>:
+ More music I've made.
+ </p>
+ </li>
+ <li>
+ <p>
+ <a href="https://youpic.com/photographer/microsoft/">photography @ youpic</a>:
+ Pictures I've taken.
+ </p>
+ </li>
+ <li>
+ <p>
+ <a href="https://www.youtube.com/playlist?list=PLYxitPB3WXb1B4zPAsj92l9ay5pBOyynt">talks @ youtube</a>:
+ Talks I've given.
+ </p>
+ </li>
+ </ul>
+ <h2>Etc.</h2>
+ <ul>
<li>
<p>
<a href="https://flower.unlimited.pizza">Flower</a>
<p>
<a href="telnet:unlimited.pizza:7777">telnet unlimited.pizza 7777</a>
<span>(2016)</span>:
- a random work of ansi art. Better with 24-bit enabled terminals. Powered by
- <a href="https://gitlab.com/rbdr/tomato-sauce">Tomato Sauce</a>.
+ a random work of ansi art. Better with 24-bit enabled terminals.
+ (<a href="https://gitlab.com/rbdr/tomato-sauce">source</a>)
</p>
</li>
<li>
<a href="https://lgtm.unlimited.pizza">LGTM</a>
<span>(2016)</span>:
Looks Good To Me! 👍
- <a aria-label="See the source of LGTM" href="https://gitlab.com/rbdr/lgtm">See the source</a>.
+ (<a aria-label="See the source of LGTM" href="https://gitlab.com/rbdr/lgtm">source</a>)
</p>
</li>
<li>
</ul>
</main>
-<aside title="More about me">
- <h1>More about me.</h1>
-
- <video autoplay muted loop aria-label="A picture of Rubén sleeping with an animated overlay changing the eyes, and showing a snake-like tongue">
- <source src="/video/selfie.webm" type="video/webm">
- <source src="/video/selfie.mp4" type="video/mp4">
- </video>
-
- <p>
- Unlimited pizza <span aria-hidden="true">🍕</span> / Rubén Beltrán del Río.
- I have words written <span lang="es-mx">(español e inglés)</span> in my
- <a href="https://blog.unlimited.pizza">blog</a>,
- spoken in <a href="https://www.youtube.com/playlist?list=PLYxitPB3WXb1B4zPAsj92l9ay5pBOyynt">a handy playlist</a>,
- music in <a href="https://soundcloud.com/benbeltran">soundcloud</a>,
- <a href="https://myspace.bandcamp.com">bandcamp</a>,
- and <a href="https://music.apple.com/us/artist/ben-beltran/1338665508">apple music</a>.
- You can find my code in <a href="https://gitlab.com/rbdr">gitlab</a>.
- I sometimes post pictures in <a href="https://youpic.com/photographer/microsoft/">youpic</a>.
- </p>
- <p>
- You can <a href="mailto:ruben+up@unlimited.pizza">write me an e-mail</a> if you
- find a cool rock you want to show me, if you want to tell a story, if
- you need a cyber high five, if robots are starting an uprising and you want us
- to join, or if you want to get together to practice your latest dance moves.
- But <a href="https://twitter.com/pigeonfolk">twitter</a> works better.
- </p>
-
- <p>🌱.🐓.⚓️</p>
+<aside title="Version">
+ <p>🦜.🌱.🪕</p>
</aside>
--- /dev/null
+(function () {
+
+ var canvas = document.querySelector('canvas');
+ var context = canvas.getContext('2d');
+ var fps = 30;
+ var lastFrame = 0;
+ var speed = 1;
+ var size = 5 + Roundom(10);
+
+ var clear = !!(Math.random() > 0.5);
+ var changeColor = !!(Math.random() > 0.5);
+ var items = Array(Roundom(10) + 6).fill(null).map(() => ({
+ x: Roundom(100),
+ y: Roundom(100),
+ angle: Math.random() * 2 * Math.PI,
+ color: Array(3).fill(null).map(() => Roundom(256))
+ }));
+ var shapes = [square, circle, heart, chaos, lineChaos];
+ var positions = [identity, spin(5), spin(15)];
+ var draw = shapes[Roundom(shapes.length)];
+ var position = positions[Roundom(positions.length)];
+
+ function Roundom (x) {
+ return Math.floor(Math.random() * x);
+ }
+
+ function square(item) {
+
+ var p = position(item);
+ context.fillRect(p.x, p.y, size, size);
+ }
+
+ function circle(item) {
+
+ var p = position(item);
+ context.beginPath();
+ context.arc(p.x, p.y, size / 2, 0, 2 * Math.PI);
+ context.fill();
+ }
+
+ function chaos(item) {
+
+ var p = position(item);
+ context.beginPath();
+ context.moveTo(p.x, p.y);
+ context.lineTo(p.x * 10 * Math.cos(item.angle), p.y * 10 * Math.sin(item.angle));
+ context.lineTo(Roundom(100), Roundom(100));
+ context.fill();
+ }
+
+ function lineChaos(item) {
+
+ var p = position(item);
+ context.beginPath();
+ context.lineWidth = 5;
+ context.strokeStyle = `rgb(${item.color.join(',')})`;
+ context.moveTo(p.x, p.y);
+ context.lineTo(p.x * 10 * Math.cos(item.angle), p.y * 10 * Math.sin(item.angle));
+ context.stroke();
+ }
+
+ function square(item) {
+
+ var p = position(item);
+ context.fillRect(p.x, p.y, size, size);
+ }
+
+ function heart(item) {
+
+ var p = position(item);
+ context.fillRect(p.x, p.y, size, size);
+
+ context.beginPath();
+ context.arc(p.x + size / 2, p.y, size / 2, 0, 2 * Math.PI, false);
+ context.fill();
+ context.closePath();
+
+ context.beginPath();
+ context.arc(p.x + size, p.y + size / 2, size / 2, 0, 2 * Math.PI, false);
+ context.fill();
+ context.closePath();
+ }
+
+ function identity(position) {
+
+ return position;
+ }
+
+ function spin(radius) {
+ return function (position) {
+
+ return {
+ x: position.x + radius * Math.cos(lastFrame),
+ y: position.y + radius * Math.sin(lastFrame)
+ }
+ }
+ }
+
+ function move(item) {
+
+ item.x = item.x + speed * Math.cos(item.angle);
+ item.y = item.y + speed * Math.sin(item.angle);
+
+ if (item.x < 0 || item.x > 100) {
+ item.angle = Math.atan2(Math.sin(item.angle), -Math.cos(item.angle))
+ }
+
+ if (item.y < 0 || item.y > 100) {
+ item.angle = Math.atan2(-Math.sin(item.angle), Math.cos(item.angle))
+ }
+ }
+
+ function updateColor(item) {
+
+ item.color = item.color.map((c) => {
+ c = c + 5;
+ return c > 255 ? 0 : c;
+ })
+ }
+
+ function frame(time) {
+
+ window.requestAnimationFrame(frame);
+
+ var delta = time - lastFrame;
+
+ if (delta > 1000 / fps) {
+ clear && context.clearRect(0, 0, 100, 100);
+ for (var item of items) {
+ context.fillStyle = `rgb(${item.color.join(',')})`;
+ draw(item);
+ changeColor && updateColor(item);
+ move(item);
+ }
+
+ lastFrame = time;
+ }
+ }
+
+ frame();
+}
+)();
+++ /dev/null
-// App Config
-
-const kEntrypoint = "breadsticks";
-const kGap = 50;
-const kDrawDelay = 100;
-const kDarkDrawingColor = '#fff';
-const kLightDrawingColor = '#000';
-const kMaxVectorMagnitude = 150; // max size of a vector
-const kMagnitudeColorMultiplier = 2.5; // how large should the magnitude be before it's completely transparent
-
-/***********************************************
- * Breadstick generates a matrix of points
- * and assigns a vector to each entry
- * and then draws them
- ***********************************************/
-
-/*
- * Generate field of points in which to draw
- */
-
-// Updates the field object using a canvas
-
-const updateFieldFromCanvas = (field, canvas) => {
- updateFieldFromRect(field, canvas.getBoundingClientRect());
-
- canvas.width = window.innerWidth;
- canvas.height = window.innerHeight;
-
- window.addEventListener('resize', () => {
- canvas.width = window.innerWidth;
- canvas.height = window.innerHeight;
- updateFieldFromRect(field, canvas.getBoundingClientRect());
- });
-};
-
-// Updates a field object using a rect
-
-const updateFieldFromRect = (field, rect) => {
- field.width = rect.width;
- field.height = rect.height;
-}
-
-/*
- * Generate the matrix of vectors
- */
-
-// Updates a matrix for a given field using the mouse
-
-
-const updateFieldMatrixFromMouse = (field, matrix, gap = 50) => {
- const mousePosition = {
- x: 0,
- y: 0
- };
-
- fillMatrix(matrix, mousePosition.x, mousePosition.y, field.width, field.height, gap);
-
- const updateMousePosition = document.addEventListener('mousemove', (event) => {
- mousePosition.x = event.clientX;
- mousePosition.y = event.clientY;
- fillMatrix(matrix, mousePosition.x, mousePosition.y, field.width, field.height, gap);
- });
-};
-
-// Gets a matrix by calculating the offset between position and field.
-
-const fillMatrix = (matrix, x, y, w, h, gap = 50) => {
- for (let i = 0; i < w / gap; ++i) {
- matrix[i] = [];
- for (let j = 0; j < h / gap; ++j) {
- let targetX = i * gap;
- let targetY = j * gap;
- matrix[i][j] = calculateOffsetVector(x, y, targetX, targetY, w, h);
- }
- }
-};
-
-// Calculates the offset vector of a point
-const calculateOffsetVector = (sourceX, sourceY, targetX, targetY, w, h) => {
- const xOffset = targetX - sourceX;
- const yOffset = targetY - sourceY;
-
- const calculatedMagnitude = Math.sqrt(Math.pow(xOffset, 2) + Math.pow(yOffset, 2));
-
- return {
- position: {
- x: targetX,
- y: targetY
- },
- color: getColor(calculatedMagnitude),
- angle: Math.atan2(xOffset, yOffset),
- magnitude: Math.min(calculatedMagnitude, kMaxVectorMagnitude)
- };
-};
-
-
-/*
- * Drawing
- */
-
-// draw a vector
-const drawVector = (context, i, j, vector) => {
- const x = vector.position.x - vector.magnitude * Math.sin(vector.angle);
- const y = vector.position.y - vector.magnitude * Math.cos(vector.angle);
- context.strokeStyle = vector.color;
- context.beginPath();
- context.moveTo(vector.position.x, vector.position.y);
- context.lineTo(Math.round(x), Math.round(y));
- context.stroke();
-};
-
-// Gets the color depending on the calculated magnitude
-// as well as the color scheme
-
-const getColor = (calculatedMagnitude) => {
-
- let colorValue = Math.round(calculatedMagnitude * 255 / (kMaxVectorMagnitude * kMagnitudeColorMultiplier)) % 255;
-
- if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
- colorValue = 255 - colorValue % 255;
- }
-
- // Initialize an array with the value, converts it to a hex string and joins it.
- return `#${Array(3).fill(colorValue.toString(16)).join('')}`;
-};
-
-
-// Draws field on canvas
-
-const drawFieldMatrixOnCanvas = (matrix, context) => {
-
- context.setLineDash([25, 10])
- context.clearRect(0, 0, context.canvas.width, context.canvas.height);
-
- for (let i = 0; i < matrix.length; ++i) {
- const row = matrix[i];
- for (let j = 0; j < row.length; ++j) {
- const vector = row[j]
-
- if (vector) {
- drawVector(context, i, j, vector);
- }
- }
- }
-};
-
-/*
- * Entrypoint
- */
-
-const run = () => {
-
- const field = {
- width: 0,
- height: 0
- };
- const canvas = document.getElementById(kEntrypoint);
-
- updateFieldFromCanvas(field, canvas);
-
- const matrix = [[]];
- updateFieldMatrixFromMouse(field, matrix, kGap);
-
- const context = canvas.getContext('2d');
- const drawFunction = () => {
- drawFieldMatrixOnCanvas(matrix, context);
- setTimeout(drawFunction, kDrawDelay);
- }
-
- setTimeout(drawFunction, 0);
-};
-
-window.addEventListener('load', run);
+++ /dev/null
-if ('serviceWorker' in navigator) {
-
- navigator.serviceWorker.register('/service_worker.js');
-}