Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions scripts/brand/directions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#!/usr/bin/env python3
"""Generates the Phase 1 logo concepts for the Entangle site, one per brand direction.

python3 scripts/brand/directions.py

Writes into site/assets/logo/ (committed):
<direction>-mark.svg the symbol alone on a 48 x 32 grid
<direction>-lockup.svg symbol + "entangle" wordmark (Inter 600, from the site's own font)

Standard library only. Every shape is computed here so a chosen direction can be refined by
changing a constant and re-running, never by hand-editing paths. Colors are the direction's
palette tokens in site/styles.css; keep the two in step.
"""

import math
from pathlib import Path

ROOT = Path(__file__).resolve().parents[2]
OUT = ROOT / "site/assets/logo"

# Palette tokens, mirrored from site/styles.css ([data-direction="…"]).
PALETTES = {
"singlet": {"ink": "#1A1A1F", "a": "#C8431F", "b": "#176B6B"},
"spacelike": {"ink": "#ECEBE6", "a": "#F0B23A", "b": "#F0B23A"},
"swap": {"ink": "#EFEBE0", "a": "#D7935B", "b": "#D7935B"},
"bound": {"ink": "#0F1B1E", "a": "#0F7A5A", "b": "#9AA7AC"},
"quadrant": {"ink": "#F1ECE2", "a": "#E9A23B", "b": "#F4E8D2"},
"crossing": {"ink": "#EDEEEA", "a": "#D9532F", "b": "#F6D4BE"},
"collapse": {"ink": "#17171B", "a": "#B8341C", "b": "#1C6E6B"},
}


def f(v):
return ("%.2f" % v).rstrip("0").rstrip(".")


def half_disc(cx, cy, r, angle_deg, side, fill):
"""One half of a disc, cut by a diameter at angle_deg; side = +1 or -1 picks the half."""
a = math.radians(angle_deg)
dx, dy = math.cos(a) * r, math.sin(a) * r
x1, y1 = cx + dx, cy + dy
x2, y2 = cx - dx, cy - dy
sweep = 1 if side > 0 else 0
return '<path d="M%s %s A%s %s 0 0 %d %s %s Z" fill="%s"/>' % (
f(x1), f(y1), f(r), f(r), sweep, f(x2), f(y2), fill)


def singlet(p):
"""Two particles in a spin singlet: measured along the same axis they are always opposite.
Each disc is cut by the same measurement axis; the filled halves are on opposite sides."""
r, ang = 10, -32
out = []
for cx, side, col in ((13, +1, p["a"]), (35, -1, p["b"])):
out.append('<circle cx="%d" cy="16" r="%d" fill="none" stroke="%s" stroke-width="1.5"/>' % (cx, r, p["ink"]))
out.append(half_disc(cx, 16, r - 0.75, ang, side, col))
return "\n".join(out)


def spacelike(p):
"""Two events outside each other's light cone. The cone is the X of a spacetime diagram
(time up); the two dots sit on one time slice, where no signal can have passed between them."""
out = ['<path d="M14 3 L34 29 M34 3 L14 29" fill="none" stroke="%s" stroke-width="1.5" stroke-linecap="round"/>' % p["ink"]]
for cx in (5, 43):
out.append('<circle cx="%d" cy="16" r="3.25" fill="%s"/>' % (cx, p["a"]))
return "\n".join(out)


def swap(p):
"""Entanglement swapping: two short-range pairs (A-R, R-C) become one long-range pair (A-C)
after a measurement at R, which is left holding nothing. The repeater in one glyph."""
y = 22
out = []
out.append('<path d="M6 %d Q15 8 24 %d Q33 8 42 %d" fill="none" stroke="%s" stroke-width="1.5" stroke-linecap="round" opacity=".45"/>' % (y, y, y, p["ink"]))
out.append('<path d="M6 %d Q24 -10 42 %d" fill="none" stroke="%s" stroke-width="2" stroke-linecap="round"/>' % (y, y, p["a"]))
out.append('<circle cx="6" cy="%d" r="3.5" fill="%s"/>' % (y, p["a"]))
out.append('<circle cx="42" cy="%d" r="3.5" fill="%s"/>' % (y, p["a"]))
out.append('<circle cx="24" cy="%d" r="3" fill="none" stroke="%s" stroke-width="1.5"/>' % (y, p["ink"]))
return "\n".join(out)


def bound(p):
"""Bell's theorem as a plot: the quantum correlation (a cosine) rising above the straight
line that is the most any local hidden-variable model can reach."""
out = []
out.append('<path d="M5 27 L24 9 L43 27" fill="none" stroke="%s" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>' % p["b"])
# -cos sampled; a smooth cosine from 5 to 43 peaking at 24.
pts = []
for i in range(0, 41):
t = i / 40
x = 5 + 38 * t
y = 27 - 23 * (0.5 - 0.5 * math.cos(2 * math.pi * t))
pts.append("%s%s %s" % ("M" if i == 0 else "L", f(x), f(y)))
out.append('<path d="%s" fill="none" stroke="%s" stroke-width="2.25" stroke-linecap="round"/>' % (" ".join(pts), p["a"]))
return "\n".join(out)


def _hash(k):
"""Deterministic pseudo-random in [0, 1); same formula as site/directions.js hash()."""
x = math.sin(k * 12.9898 + 78.233) * 43758.5453
return x - math.floor(x)


def quadrant(p):
"""The Glasgow 2019 Bell image: a ring whose four quadrants carry phase-shifted patterns.
Drawn as four quadrant arcs at alternating radii, the shift between settings made literal."""
out = ['<circle cx="24" cy="16" r="11" fill="none" stroke="%s" stroke-width="1" opacity="0.35"/>' % p["ink"]]
radii = [11.5, 9.5, 11.5, 9.5]
for q in range(4):
a0, a1, r = q * math.pi / 2 + 0.12, (q + 1) * math.pi / 2 - 0.12, radii[q]
out.append('<path d="M%s %s A%s %s 0 0 1 %s %s" fill="none" stroke="%s" stroke-width="3" stroke-linecap="round"/>'
% (f(24 + r * math.cos(a0)), f(16 + r * math.sin(a0)), f(r), f(r),
f(24 + r * math.cos(a1)), f(16 + r * math.sin(a1)), p["b"] if q % 2 else p["a"]))
return "\n".join(out)


def crossing(p):
"""Type-II SPDC: two offset rings of down-converted light; the entangled pairs are born
where the rings cross, so the two crossing points are the only filled shapes."""
y = math.sqrt(10 ** 2 - 6 ** 2)
return "\n".join([
'<circle cx="18" cy="16" r="10" fill="none" stroke="%s" stroke-width="1.75"/>' % p["a"],
'<circle cx="30" cy="16" r="10" fill="none" stroke="%s" stroke-width="1.75"/>' % p["a"],
'<circle cx="24" cy="%s" r="2.4" fill="%s"/>' % (f(16 - y), p["b"]),
'<circle cx="24" cy="%s" r="2.4" fill="%s"/>' % (f(16 + y), p["b"]),
])


def collapse(p):
"""Two probability clouds as stippled densities, already collapsed to complementary
outcomes: the left cloud sits high, the right one low. No line joins them."""
out = []
for side in range(2):
cx, col = (34 if side else 14), (p["b"] if side else p["a"])
for i in range(26):
r = math.sqrt(_hash(side * 50 + i + 0.2)) * 9
th = _hash(side * 50 + i + 0.7) * math.pi * 2
out.append('<circle cx="%s" cy="%s" r="%s" fill="%s"/>'
% (f(cx + math.cos(th) * r), f(16 + math.sin(th) * r * 0.75 + (4 if side else -4)),
f(0.9 + _hash(i + side) * 0.9), col))
return "\n".join(out)


MARKS = {"singlet": singlet, "spacelike": spacelike, "swap": swap, "bound": bound,
"quadrant": quadrant, "crossing": crossing, "collapse": collapse}


def svg(w, h, body, extra=""):
return ('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 %d %d" width="%d" height="%d"%s>\n%s\n</svg>\n'
% (w, h, w, h, extra, body))


def main():
OUT.mkdir(parents=True, exist_ok=True)
for name, fn in MARKS.items():
p = PALETTES[name]
mark = fn(p)
(OUT / ("%s-mark.svg" % name)).write_text(svg(48, 32, mark, ' role="img" aria-label="Entangle"'))
word = ('<text x="58" y="23.5" font-family="Inter, ui-sans-serif, system-ui, sans-serif" font-size="22" '
'font-weight="600" letter-spacing="-0.44" fill="%s">entangle</text>' % p["ink"])
(OUT / ("%s-lockup.svg" % name)).write_text(svg(152, 32, mark + "\n" + word, ' role="img" aria-label="Entangle"'))
print("wrote", name)


if __name__ == "__main__":
main()
40 changes: 40 additions & 0 deletions site/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Entangle website

Static site for https://daileng.github.io/entangle/ (GitHub Pages, `/entangle/` base path; all
asset references are relative so a custom domain needs no changes). No build step, no framework,
no third-party requests: Inter is self-hosted from `assets/fonts/`, Lucide glyphs are inlined in
`index.html`.

Type scale, spacing, radii and icon rules follow the tachyon design system
(DailenG/tachyon, `docs/design/system/`). The palette and the mark are Entangle's own.

## Phase 1: directions

`index.html` currently shows four switchable brand directions. Switching changes the palette
(`html[data-direction]` in `styles.css`), the header mark, the hero copy and the hero animation
(`directions.js`). Desktop: the labelled "Direction" pill in the bottom-right corner. Phones: the
pill under the hero visual, or tap the visual. Keys `1`–`7` switch, `Q` toggles quarter speed. First load opens on `quadrant` (the working lead); a returning visitor gets their last pick.
Query parameters: `?d=<id>&speed=quarter`, plus `&t=<seconds>&picker=open` for captures.

| # | id | Physics | Palette (role: hex) |
|---|----|---------|---------------------|
| 1 | `singlet` | Spin singlet: the same axis measured on both particles always gives opposite results | bg `#F5F1E8`, ink `#1A1A1F`, body `#44454D`, muted `#6B6C75`, A `#C8431F`, B `#176B6B` |
| 2 | `spacelike` | Minkowski diagram: two simultaneous outcomes whose light cones have not met | bg `#0F1115`, ink `#ECEBE6`, body `#B4B6BC`, muted `#868A93`, trace `#F0B23A` |
| 3 | `swap` | Entanglement swapping: a Bell measurement at the repeater entangles A and C, which never met | bg `#1F2B27`, chalk `#EFEBE0`, body `#C7C3B7`, muted `#9A988D`, copper `#D7935B`, slate `#8FB8C9` |
| 4 | `bound` | Bell's inequality: measured correlation E(θ) rising above the local-realist straight line | bg `#F2F5F6`, ink `#0F1B1E`, body `#3C4A4F`, muted `#627179`, trace `#0F7A5A`, bound `#9AA7AC` |
| 5 | `quadrant` | The Glasgow 2019 Bell image (Moreau et al.): photon A's interference pattern, built from single detections, shifts in each quadrant with the phase filter applied to photon B | bg `#121113`, ink `#F1ECE2`, body `#BDB7AC`, muted `#8E887E`, amber `#E9A23B`, warm white `#F4E8D2` |
| 6 | `crossing` | Type-II SPDC (Kwiat et al. 1995): two offset rings of down-converted light; the polarisation-entangled pairs are born where the rings cross | bg `#14181B`, ink `#EDEEEA`, body `#B7BCBB`, muted `#87908F`, ember `#D9532F`, peach `#F6D4BE` |
| 7 | `collapse` | Two probability clouds that fluctuate independently and collapse in the same frame to complementary outcomes; nothing travels between them | bg `#F4F0E7`, ink `#17171B`, body `#44454C`, muted `#6D6E76`, vermilion `#B8341C`, teal `#1C6E6B` |

Marks are generated by `scripts/brand/directions.py` into `assets/logo/`; the header draws the
same geometry inline so it recolors with the direction.

Motion respects `prefers-reduced-motion` (a still frame is drawn instead) and pauses when the
canvas is off-screen or the tab is hidden.

## Local preview

```sh
mkdir -p /tmp/srv && ln -sfn "$PWD/site" /tmp/srv/entangle && (cd /tmp/srv && python3 -m http.server 8765)
# open http://localhost:8765/entangle/
```
92 changes: 92 additions & 0 deletions site/assets/fonts/Inter-LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL

-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION AND CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file added site/assets/fonts/inter-latin.woff2
Binary file not shown.
15 changes: 15 additions & 0 deletions site/assets/icons/Lucide-LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ISC License

Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of Feather (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2022.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
5 changes: 5 additions & 0 deletions site/assets/logo/bound-lockup.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions site/assets/logo/bound-mark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading