mirror of
https://github.com/TinyTapeout/tt-support-tools.git
synced 2026-11-03 12:46:08 +01:00
product datasheet in progress
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
# Build outputs — regenerate with build.py
|
||||
tt-datasheet.html
|
||||
tt-datasheet.pdf
|
||||
.tt-datasheet.chrome.html
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2020 The Archivo Project Authors (https://github.com/Omnibus-Type/Archivo)
|
||||
|
||||
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 & 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.
|
||||
@@ -0,0 +1,13 @@
|
||||
# Datasheet assets
|
||||
|
||||
Both files are embedded as data URIs by `build.py`, so the generated HTML is
|
||||
self-contained. Swap either one by dropping in a replacement and updating the
|
||||
`assets:` block in `datasheet.yaml`.
|
||||
|
||||
| File | Source | Licence |
|
||||
| ---- | ------ | ------- |
|
||||
| `archivo.woff2` | [Archivo](https://github.com/Omnibus-Type/Archivo) via Google Fonts, latin subset, variable weight 100–900 | SIL Open Font License 1.1 — see `OFL.txt` |
|
||||
| `demoboard.jpg` | Tiny Tapeout ETR demoboard quickstart guide, downscaled to 1000px | © 2024 Pat Deegan, psychogenic.com — **not** covered by this repo's Apache-2.0 licence |
|
||||
|
||||
The demoboard photo is credited in the datasheet caption. Confirm redistribution
|
||||
is agreed with the copyright holder before publishing the datasheet externally.
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 139 KiB |
@@ -0,0 +1,257 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build the two-page Tiny Tapeout product datasheet.
|
||||
|
||||
All copy, numbers and colours live in datasheet.yaml. This script renders them
|
||||
through datasheet.html.mustache, inlining the font and photo as data URIs so the
|
||||
result is a single self-contained file that prints to two A4 pages.
|
||||
|
||||
python3 docs/product/build.py # write tt-datasheet.html
|
||||
python3 docs/product/build.py --pdf # also render tt-datasheet.pdf
|
||||
|
||||
The sheets are a fixed 297mm tall with overflow hidden, so copy that grows too
|
||||
long is silently clipped rather than spilling onto a third page. Every build
|
||||
therefore measures the rendered sheets in headless Chrome and fails if anything
|
||||
overflows. Pass --no-check to skip that (or set CHROME if it isn't found).
|
||||
|
||||
Requires chevron and pyyaml, both already pinned in requirements.txt.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import chevron
|
||||
import yaml
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
|
||||
# `style` tokens in datasheet.yaml -> CSS classes in the template.
|
||||
STYLE_CLASSES = {
|
||||
"name": "t-name",
|
||||
"mono": "t-mono",
|
||||
"num": "t-num",
|
||||
"price": "t-price",
|
||||
"dim": "t-dim",
|
||||
"center": "t-center",
|
||||
}
|
||||
|
||||
# Tables are rendered through partials/table.mustache and need preparing first.
|
||||
TABLE_KEYS = ["pricing", "process", "ratings", "gpio", "analog", "ordering"]
|
||||
|
||||
EM_DASH = "—"
|
||||
|
||||
CHROME_CANDIDATES = [
|
||||
os.environ.get("CHROME"),
|
||||
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
||||
"google-chrome",
|
||||
"chromium",
|
||||
]
|
||||
|
||||
|
||||
def cell_classes(style: str, value: str) -> str:
|
||||
"""Map a column's style tokens to CSS classes for one cell."""
|
||||
classes = []
|
||||
for token in style.split():
|
||||
try:
|
||||
classes.append(STYLE_CLASSES[token])
|
||||
except KeyError:
|
||||
raise SystemExit(
|
||||
f"unknown style '{token}' — expected one of {', '.join(STYLE_CLASSES)}"
|
||||
)
|
||||
# A lone em dash means "not applicable"; grey it out wherever it appears.
|
||||
if value.strip() == EM_DASH and "t-dim" not in classes:
|
||||
classes.append("t-dim")
|
||||
return " ".join(classes)
|
||||
|
||||
|
||||
def prepare_table(name: str, table: dict) -> None:
|
||||
"""Expand a table's columns and rows into what the template expects."""
|
||||
columns = table.get("columns") or []
|
||||
for column in columns:
|
||||
width = column.get("width")
|
||||
column["width_attr"] = f' style="width:{width}"' if width else ""
|
||||
column.setdefault("label", "")
|
||||
|
||||
styles = [column.get("style", "") for column in columns]
|
||||
|
||||
rows = []
|
||||
for index, row in enumerate(table.get("rows") or [], start=1):
|
||||
if len(row) != len(columns):
|
||||
raise SystemExit(
|
||||
f"{name}: row {index} has {len(row)} cells "
|
||||
f"but there are {len(columns)} columns"
|
||||
)
|
||||
rows.append(
|
||||
{
|
||||
"cells": [
|
||||
{"v": value, "cls": cell_classes(style, value)}
|
||||
for style, value in zip(styles, row)
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
table["rows"] = rows
|
||||
table["has_note"] = bool(table.get("note"))
|
||||
table["has_footnote"] = bool(table.get("footnote"))
|
||||
|
||||
|
||||
def as_data_uri_payload(path: Path) -> str:
|
||||
if not path.is_file():
|
||||
raise SystemExit(f"missing asset: {path}")
|
||||
return base64.b64encode(path.read_bytes()).decode()
|
||||
|
||||
|
||||
def find_chrome() -> str:
|
||||
for candidate in CHROME_CANDIDATES:
|
||||
if candidate and (Path(candidate).is_file() or shutil.which(candidate)):
|
||||
return candidate
|
||||
raise SystemExit(
|
||||
"could not find Chrome — set the CHROME environment variable to its path"
|
||||
)
|
||||
|
||||
|
||||
MEASURE_SCRIPT = """
|
||||
<div id="fit-report">pending</div>
|
||||
<script>
|
||||
window.addEventListener("load", () => setTimeout(() => {
|
||||
const mm = 25.4 / 96;
|
||||
const report = [...document.querySelectorAll(".sheet")].map((sheet, i) => {
|
||||
const body = sheet.querySelector(".body");
|
||||
return [i + 1, ((body.scrollHeight - body.clientHeight) * mm).toFixed(1)].join(":");
|
||||
});
|
||||
document.getElementById("fit-report").textContent = report.join(",");
|
||||
}, 500));
|
||||
</script>
|
||||
"""
|
||||
|
||||
|
||||
def run_chrome(*flags: str, page: Path) -> bytes:
|
||||
result = subprocess.run(
|
||||
[
|
||||
find_chrome(),
|
||||
"--headless",
|
||||
"--disable-gpu",
|
||||
"--no-sandbox",
|
||||
*flags,
|
||||
page.resolve().as_uri(),
|
||||
],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
)
|
||||
return result.stdout
|
||||
|
||||
|
||||
def as_document(html_path: Path, extra: str = "") -> Path:
|
||||
"""Chrome needs a complete document; the published artifact is wrapped for us."""
|
||||
wrapped = html_path.with_name("." + html_path.stem + ".chrome.html")
|
||||
wrapped.write_text(
|
||||
"<!doctype html><html><head><meta charset='utf-8'>"
|
||||
"<style>*{margin:0;padding:0}</style></head><body>"
|
||||
+ html_path.read_text(encoding="utf-8")
|
||||
+ extra
|
||||
+ "</body></html>",
|
||||
encoding="utf-8",
|
||||
)
|
||||
return wrapped
|
||||
|
||||
|
||||
def check_fit(html_path: Path) -> bool:
|
||||
"""Measure each sheet in Chrome; report how far any of them overflows."""
|
||||
page = as_document(html_path, MEASURE_SCRIPT)
|
||||
try:
|
||||
dom = run_chrome("--virtual-time-budget=5000", "--dump-dom", page=page)
|
||||
finally:
|
||||
page.unlink(missing_ok=True)
|
||||
|
||||
found = re.search(rb'<div id="fit-report">([^<]*)</div>', dom)
|
||||
if not found or found.group(1) == b"pending":
|
||||
logging.warning("could not measure sheet fit — skipping check")
|
||||
return True
|
||||
|
||||
overflowed = False
|
||||
for entry in found.group(1).decode().split(","):
|
||||
sheet, overflow = entry.split(":")
|
||||
if float(overflow) > 0:
|
||||
overflowed = True
|
||||
logging.error(
|
||||
f"page {sheet} overflows by {overflow}mm — content past the bottom "
|
||||
"of the sheet is CLIPPED, not moved to another page"
|
||||
)
|
||||
else:
|
||||
logging.info(f"page {sheet} fits")
|
||||
if overflowed:
|
||||
logging.error("trim copy in datasheet.yaml, or shorten a table")
|
||||
return not overflowed
|
||||
|
||||
|
||||
def render_pdf(html_path: Path, pdf_path: Path) -> None:
|
||||
page = as_document(html_path)
|
||||
try:
|
||||
run_chrome("--no-pdf-header-footer", f"--print-to-pdf={pdf_path}", page=page)
|
||||
finally:
|
||||
page.unlink(missing_ok=True)
|
||||
pages = len(re.findall(rb"/Type\s*/Page[^s]", pdf_path.read_bytes()))
|
||||
logging.info(f"wrote {pdf_path} ({pages} pages)")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--config", default=HERE / "datasheet.yaml", type=Path, help="content YAML"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out", default=HERE / "tt-datasheet.html", type=Path, help="output HTML"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--pdf", action="store_true", help="also render a PDF next to the HTML"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-check",
|
||||
dest="check",
|
||||
action="store_false",
|
||||
help="skip the headless-Chrome overflow check",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO, format="%(levelname)-8s %(message)s", stream=sys.stdout
|
||||
)
|
||||
|
||||
with open(args.config, encoding="utf-8") as fh:
|
||||
content = yaml.safe_load(fh)
|
||||
|
||||
for key in TABLE_KEYS:
|
||||
if key not in content:
|
||||
raise SystemExit(f"{args.config}: missing '{key}' section")
|
||||
prepare_table(key, content[key])
|
||||
|
||||
assets = HERE / "assets"
|
||||
content["font_b64"] = as_data_uri_payload(assets / content["assets"]["font"])
|
||||
content["photo_b64"] = as_data_uri_payload(assets / content["assets"]["photo"])
|
||||
|
||||
with open(HERE / "datasheet.html.mustache", encoding="utf-8") as fh:
|
||||
rendered = chevron.render(
|
||||
fh.read(),
|
||||
content,
|
||||
partials_path=str(HERE / "partials"),
|
||||
partials_ext="mustache",
|
||||
)
|
||||
|
||||
args.out.write_text(rendered, encoding="utf-8")
|
||||
logging.info(f"wrote {args.out} ({len(rendered) / 1024:.0f} KB)")
|
||||
|
||||
if args.pdf:
|
||||
render_pdf(args.out, args.out.with_suffix(".pdf"))
|
||||
|
||||
if args.check and not check_fit(args.out):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,486 @@
|
||||
<title>{{&doc.title}}</title>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: "Archivo";
|
||||
src: url(data:font/woff2;base64,{{&font_b64}}) format("woff2");
|
||||
font-weight: 100 900;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
}
|
||||
|
||||
:root {
|
||||
--navy: {{theme.navy}};
|
||||
--red: {{theme.red}};
|
||||
--ink: {{theme.ink}};
|
||||
--ink-mid: {{theme.ink_mid}};
|
||||
--ink-faint: {{theme.ink_faint}};
|
||||
--ground: {{theme.ground}};
|
||||
--rule: {{theme.rule}};
|
||||
--rule-hard: {{theme.rule_hard}};
|
||||
--paper: #ffffff;
|
||||
--chrome: #d8d7dd;
|
||||
|
||||
--t-micro: 6.2pt;
|
||||
--t-fine: 7.1pt;
|
||||
--t-body: {{theme.body_size}};
|
||||
--t-lead: 9.6pt;
|
||||
--t-sub: 13pt;
|
||||
--t-h2: 15pt;
|
||||
--t-h1: {{theme.heading_size}};
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) { :root { --chrome: #17171c; } }
|
||||
:root[data-theme="dark"] { --chrome: #17171c; }
|
||||
:root[data-theme="light"] { --chrome: #d8d7dd; }
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--chrome);
|
||||
font-family: "Archivo", "Helvetica Neue", Arial, sans-serif;
|
||||
color: var(--ink);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.deck {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8mm;
|
||||
padding: 8mm 4mm;
|
||||
}
|
||||
|
||||
.sheet {
|
||||
width: 210mm;
|
||||
height: 297mm;
|
||||
background: var(--paper);
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
/* ---------- masthead ---------- */
|
||||
|
||||
.bar {
|
||||
background: var(--navy);
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5mm;
|
||||
padding: 4.2mm 12mm;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.bar__logo { width: 11mm; height: 11mm; flex: none; display: block; }
|
||||
|
||||
.bar__word {
|
||||
font-size: var(--t-sub);
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.01em;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.bar__word span { display: block; font-size: var(--t-micro); font-weight: 600; letter-spacing: 0.14em; color: #9a99d6; margin-top: 1.1mm; }
|
||||
|
||||
.bar__tag {
|
||||
margin-left: auto;
|
||||
background: var(--red);
|
||||
color: #fff;
|
||||
font-size: var(--t-fine);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.16em;
|
||||
padding: 1.4mm 3mm;
|
||||
}
|
||||
|
||||
.bar__ref { font-size: var(--t-micro); font-weight: 500; letter-spacing: 0.1em; color: #9a99d6; font-variant-numeric: tabular-nums; }
|
||||
|
||||
.bar--p2 .bar__title { margin-left: auto; font-size: var(--t-fine); font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; }
|
||||
|
||||
/* ---------- shared structure ---------- */
|
||||
|
||||
.body {
|
||||
flex: 1 1 auto;
|
||||
padding: 0 12mm;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: var(--t-micro);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.16em;
|
||||
text-transform: uppercase;
|
||||
color: var(--red);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.label--dim { color: var(--ink-faint); }
|
||||
|
||||
.secthead {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 3mm;
|
||||
border-bottom: 2px solid var(--rule-hard);
|
||||
padding-bottom: 1.1mm;
|
||||
margin-bottom: 2.1mm;
|
||||
}
|
||||
|
||||
.secthead h2 {
|
||||
margin: 0;
|
||||
font-size: var(--t-h2);
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.015em;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.secthead .note { margin-left: auto; font-size: var(--t-micro); font-weight: 500; letter-spacing: 0.06em; color: var(--ink-faint); }
|
||||
|
||||
/* ---------- hero ---------- */
|
||||
|
||||
.hero {
|
||||
display: grid;
|
||||
grid-template-columns: 1.32fr 1fr;
|
||||
gap: 7mm;
|
||||
padding: 4.6mm 0 4.2mm;
|
||||
border-bottom: 2px solid var(--rule-hard);
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
margin: 2.2mm 0 0;
|
||||
font-size: var(--t-h1);
|
||||
font-weight: 700;
|
||||
line-height: 0.97;
|
||||
letter-spacing: -0.03em;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
.hero p {
|
||||
margin: 3mm 0 0;
|
||||
font-size: var(--t-lead);
|
||||
line-height: 1.4;
|
||||
color: var(--ink);
|
||||
max-width: 62ch;
|
||||
}
|
||||
|
||||
.hero .rule { height: 2px; background: var(--red); width: 22mm; margin-top: 3.2mm; }
|
||||
|
||||
.hero figure { margin: 0; display: flex; flex-direction: column; }
|
||||
|
||||
.hero img { width: 100%; height: 44mm; object-fit: cover; display: block; }
|
||||
|
||||
.hero figcaption {
|
||||
font-size: var(--t-micro);
|
||||
color: var(--ink-faint);
|
||||
letter-spacing: 0.05em;
|
||||
margin-top: 1.4mm;
|
||||
border-top: 1px solid var(--rule);
|
||||
padding-top: 1.2mm;
|
||||
}
|
||||
|
||||
/* ---------- feature grid ---------- */
|
||||
|
||||
.features {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
border-bottom: 2px solid var(--rule-hard);
|
||||
}
|
||||
|
||||
.feature {
|
||||
padding: 2.8mm 4mm 2.9mm 0;
|
||||
border-right: 1px solid var(--rule);
|
||||
}
|
||||
|
||||
.feature:nth-child(3n) { border-right: 0; padding-right: 0; }
|
||||
.feature:nth-child(n + 4) { border-top: 1px solid var(--rule); }
|
||||
|
||||
.feature h3 {
|
||||
margin: 1.6mm 0 1.4mm;
|
||||
font-size: var(--t-body);
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.005em;
|
||||
line-height: 1.12;
|
||||
}
|
||||
|
||||
.feature p { margin: 0; font-size: var(--t-fine); line-height: 1.36; color: var(--ink-mid); }
|
||||
|
||||
/* ---------- tables ---------- */
|
||||
|
||||
table { width: 100%; border-collapse: collapse; }
|
||||
|
||||
th {
|
||||
background: var(--navy);
|
||||
color: #fff;
|
||||
font-size: var(--t-micro);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.13em;
|
||||
text-transform: uppercase;
|
||||
text-align: left;
|
||||
padding: 1.35mm 2.4mm;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: var(--t-fine);
|
||||
line-height: 1.3;
|
||||
padding: 1.35mm 2.4mm;
|
||||
border-bottom: 1px solid var(--rule);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
tbody tr:last-child td { border-bottom: 0; }
|
||||
|
||||
.t-num { font-variant-numeric: tabular-nums; }
|
||||
.t-name { font-weight: 600; white-space: nowrap; }
|
||||
.t-mono { font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: 0.01em; white-space: nowrap; }
|
||||
.t-price { font-weight: 700; color: var(--red); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
||||
.t-dim { color: var(--ink-faint); }
|
||||
.t-center { text-align: center; }
|
||||
.t-sub { color: var(--ink-faint); font-weight: 500; }
|
||||
|
||||
.zebra tbody tr:nth-child(odd) td { background: var(--ground); }
|
||||
|
||||
.tnote {
|
||||
font-size: var(--t-micro);
|
||||
line-height: 1.4;
|
||||
color: var(--ink-mid);
|
||||
border-left: 2px solid var(--red);
|
||||
padding: 0 0 0 2.6mm;
|
||||
margin-top: 1.9mm;
|
||||
}
|
||||
|
||||
.tnote b { color: var(--ink); font-weight: 700; }
|
||||
|
||||
/* ---------- pricing / faq blocks ---------- */
|
||||
|
||||
.block { padding: 3.2mm 0; border-bottom: 2px solid var(--rule-hard); }
|
||||
.block:last-of-type { border-bottom: 0; }
|
||||
|
||||
.faq {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
column-gap: 8mm;
|
||||
row-gap: 2.6mm;
|
||||
}
|
||||
|
||||
.faq > div { border-top: 1px solid var(--rule); padding-top: 1.8mm; }
|
||||
|
||||
.faq h3 {
|
||||
margin: 0 0 1.2mm;
|
||||
font-size: var(--t-body);
|
||||
font-weight: 700;
|
||||
line-height: 1.15;
|
||||
letter-spacing: -0.005em;
|
||||
}
|
||||
|
||||
.faq p { margin: 0; font-size: var(--t-fine); line-height: 1.36; color: var(--ink-mid); }
|
||||
|
||||
/* ---------- page 2 two-column band ---------- */
|
||||
|
||||
.band { display: grid; grid-template-columns: 1.05fr 1fr; gap: 8mm; }
|
||||
|
||||
.band__col { display: flex; flex-direction: column; min-width: 0; }
|
||||
|
||||
.linkline {
|
||||
font-size: var(--t-micro);
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--ink-faint);
|
||||
margin-top: auto;
|
||||
padding-top: 1.4mm;
|
||||
border-top: 1px solid var(--rule);
|
||||
}
|
||||
|
||||
.linkline b { color: var(--red); font-weight: 700; }
|
||||
|
||||
a { color: inherit; text-decoration: none; }
|
||||
a:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
|
||||
@media screen { .tnote a, .note a { text-decoration: underline; text-underline-offset: 1.5px; } }
|
||||
|
||||
/* ---------- footers ---------- */
|
||||
|
||||
.foot {
|
||||
flex: none;
|
||||
padding: 3.4mm 12mm 5mm;
|
||||
border-top: 2px solid var(--rule-hard);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 6mm;
|
||||
}
|
||||
|
||||
.foot__body { flex: 1 1 auto; min-width: 0; }
|
||||
|
||||
.orgs {
|
||||
margin-top: 1.8mm;
|
||||
font-size: var(--t-fine);
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
color: var(--ink);
|
||||
column-count: 2;
|
||||
column-gap: 8mm;
|
||||
}
|
||||
|
||||
.orgs span { display: block; white-space: nowrap; }
|
||||
.orgs span::before { content: "▪"; color: var(--red); margin-right: 1.6mm; font-size: 0.8em; }
|
||||
|
||||
.disclaimer { margin-top: 1.8mm; font-size: var(--t-micro); line-height: 1.45; color: var(--ink-mid); max-width: 150mm; }
|
||||
|
||||
.pageno {
|
||||
flex: none;
|
||||
font-size: var(--t-h2);
|
||||
font-weight: 700;
|
||||
font-variant-numeric: tabular-nums;
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 0.9;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.pageno span { display: block; font-size: var(--t-micro); font-weight: 600; letter-spacing: 0.14em; color: var(--ink-faint); margin-bottom: 1mm; }
|
||||
|
||||
/* ---------- print ---------- */
|
||||
|
||||
@page { size: A4; margin: 0; }
|
||||
|
||||
@media print {
|
||||
body { background: #fff; }
|
||||
.deck { display: block; gap: 0; padding: 0; }
|
||||
.sheet { break-after: page; page-break-after: always; box-shadow: none; }
|
||||
.sheet:last-child { break-after: auto; page-break-after: auto; }
|
||||
th, .bar, .bar__tag, .zebra tbody tr:nth-child(odd) td {
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen {
|
||||
.sheet { border: 1px solid var(--rule); }
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="deck">
|
||||
|
||||
<!-- ========================= PAGE 1 ========================= -->
|
||||
<section class="sheet">
|
||||
|
||||
<header class="bar">
|
||||
{{> logo}}
|
||||
<div class="bar__word">{{&doc.wordmark}}<span>{{&doc.wordmark_sub}}</span></div>
|
||||
<div class="bar__tag">{{&doc.tag}}</div>
|
||||
<div class="bar__ref">{{&doc.ref}}</div>
|
||||
</header>
|
||||
|
||||
<div class="body">
|
||||
|
||||
<div class="hero">
|
||||
<div>
|
||||
<div class="label">{{&hero.eyebrow}}</div>
|
||||
<h1>{{&hero.heading}}</h1>
|
||||
<p>{{&hero.body}}</p>
|
||||
<div class="rule"></div>
|
||||
</div>
|
||||
<figure>
|
||||
<img src="data:image/jpeg;base64,{{&photo_b64}}" alt="{{hero.photo_alt}}">
|
||||
<figcaption>{{&hero.photo_caption}}</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="features">
|
||||
{{#features}}
|
||||
<div class="feature">
|
||||
<div class="label label--dim">{{&kicker}}</div>
|
||||
<h3>{{&title}}</h3>
|
||||
<p>{{&body}}</p>
|
||||
</div>
|
||||
{{/features}}
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
{{#pricing}}{{> secthead}}{{> table}}{{> footnote}}{{/pricing}}
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
{{#faq}}
|
||||
{{> secthead}}
|
||||
<div class="faq">
|
||||
{{#items}}
|
||||
<div>
|
||||
<h3>{{&q}}</h3>
|
||||
<p>{{&a}}</p>
|
||||
</div>
|
||||
{{/items}}
|
||||
</div>
|
||||
{{/faq}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<footer class="foot">
|
||||
<div class="foot__body">
|
||||
<div class="label label--dim">{{&institutions.label}}</div>
|
||||
<div class="orgs">
|
||||
{{#institutions.items}}<span>{{&.}}</span>
|
||||
{{/institutions.items}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageno"><span>PAGE</span>01</div>
|
||||
</footer>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- ========================= PAGE 2 ========================= -->
|
||||
<section class="sheet">
|
||||
|
||||
<header class="bar bar--p2">
|
||||
{{> logo}}
|
||||
<div class="bar__word">{{&doc.wordmark}}<span>{{&doc.ref}}</span></div>
|
||||
<div class="bar__title">{{&doc.page2_title}}</div>
|
||||
</header>
|
||||
|
||||
<div class="body">
|
||||
|
||||
<div class="block">
|
||||
{{#process}}{{> secthead}}{{> table}}{{> footnote}}{{/process}}
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
{{#ratings}}{{> secthead}}{{> table}}{{> footnote}}{{/ratings}}
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
<div class="band">
|
||||
<div class="band__col">
|
||||
{{#gpio}}
|
||||
{{> secthead}}
|
||||
{{> table}}
|
||||
<div class="linkline">{{&linkline}}</div>
|
||||
{{/gpio}}
|
||||
</div>
|
||||
<div class="band__col">
|
||||
{{#analog}}
|
||||
{{> secthead}}
|
||||
{{> table}}
|
||||
<div class="linkline">{{&linkline}}</div>
|
||||
{{/analog}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
{{#ordering}}{{> secthead}}{{> table}}{{> footnote}}{{/ordering}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<footer class="foot">
|
||||
<div class="foot__body">
|
||||
<div class="label label--dim">{{&disclaimer.label}}</div>
|
||||
<p class="disclaimer">{{&disclaimer.body}}</p>
|
||||
</div>
|
||||
<div class="pageno"><span>PAGE</span>02</div>
|
||||
</footer>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,265 @@
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tiny Tapeout product datasheet — all copy, numbers and colours.
|
||||
#
|
||||
# Edit this file, then rebuild:
|
||||
# python3 docs/product/build.py
|
||||
#
|
||||
# Notes for editing:
|
||||
# - Every text field is rendered as raw HTML, so <b>, <br> and <a href="...">
|
||||
# work anywhere. Write a literal ampersand as &.
|
||||
# - Table `style` tokens set cell formatting, space separated:
|
||||
# name bold, no wrapping (first column of most tables)
|
||||
# mono bold + tabular figures (dimensions, values, signal names)
|
||||
# num tabular figures (aligned digits)
|
||||
# price bold red + no wrapping (pricing column)
|
||||
# dim greyed out (em dashes, secondary text)
|
||||
# center centre aligned
|
||||
# - Table rows must have the same number of cells as there are columns.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
doc:
|
||||
title: Tiny Tapeout — Datasheet
|
||||
wordmark: Tiny Tapeout
|
||||
wordmark_sub: SHARED SILICON ASIC SHUTTLE
|
||||
tag: DATASHEET
|
||||
ref: DOC TT-DS-2026 · REV A
|
||||
page2_title: Electrical & Mechanical Specifications
|
||||
|
||||
# Colours and the two page-level type sizes. Everything else scales from these.
|
||||
theme:
|
||||
navy: "#040371" # header bars and table header rows
|
||||
red: "#ec3013" # accent: labels, rules, prices
|
||||
ink: "#141414" # body text
|
||||
ink_mid: "#55545f" # secondary text
|
||||
ink_faint: "#86858f" # captions, dashes
|
||||
ground: "#f2f1f4" # zebra stripe on tables
|
||||
rule: "#c9c8d0" # thin rules
|
||||
rule_hard: "#141414" # 2px section rules
|
||||
heading_size: 30pt # page 1 headline
|
||||
body_size: 8.3pt # feature and FAQ body text
|
||||
|
||||
assets:
|
||||
# Relative to docs/product/assets/. Swap either file and rebuild.
|
||||
photo: demoboard.jpg
|
||||
font: archivo.woff2
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# PAGE 1
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
hero:
|
||||
eyebrow: Shared multi-project chip · SKY130 / SG13G2 / GF180MCU
|
||||
heading: From idea to chip design in minutes
|
||||
body: >-
|
||||
Tiny Tapeout makes it more accessible than ever to get your designs manufactured on a real chip.
|
||||
Submit from a
|
||||
GitHub repository and we handle integration, tapeout, packaging and delivery.
|
||||
photo_alt: Tiny Tapeout ETR demoboard with a QFN-64 packaged ASIC on a breakout board
|
||||
photo_caption: Demoboard with QFN-64 packaged die on breakout carrier.
|
||||
|
||||
features:
|
||||
- kicker: 01 · Toolchain
|
||||
title: Local tool install optional
|
||||
body: >-
|
||||
The whole flow can run in GitHub Actions. Push your repository and your design
|
||||
is hardened in the cloud — nothing to install, no licences to buy.
|
||||
- kicker: 02 · Languages
|
||||
title: HDL agnostic
|
||||
body: >-
|
||||
Any language that can produce Verilog RTL. Project templates and CI are
|
||||
supplied for Verilog, with community provided VHDL and Chisel.
|
||||
- kicker: 03 · I/O
|
||||
title: 26 pins, plus analog
|
||||
body: >-
|
||||
Clock, reset, 8 dedicated inputs, 8 dedicated outputs and 8 bidirectional
|
||||
pins — plus up to 6 analog pins where the process allows.
|
||||
- kicker: 04 · Process
|
||||
title: Three PDKs
|
||||
body: >-
|
||||
SkyWater SKY130, IHP sg13g2 and GlobalFoundries gf180mcu. Open-source PDKs
|
||||
running multiple times per year.
|
||||
- kicker: 05 · Hardware
|
||||
title: Demoboard available
|
||||
body: >-
|
||||
An optional RP2350-based demoboard carries your packaged chip and selects
|
||||
any project on the die over USB.
|
||||
- kicker: 06 · Flexibility
|
||||
title: Bring your own flow
|
||||
body: >-
|
||||
Harden with the supplied open-source LibreLane flow, or use your own tools
|
||||
entirely — the minimum submission is GDS + LEF.
|
||||
|
||||
pricing:
|
||||
heading: Pricing
|
||||
note: INDICATIVE FROM-PRICES · EUR
|
||||
columns:
|
||||
- {label: Item, width: "27%", style: name}
|
||||
- {label: What it buys you}
|
||||
- {label: From, width: "26%", style: price}
|
||||
rows:
|
||||
- ["1 tile",
|
||||
"Roughly 1,000 standard cells of silicon area. Physical dimensions vary by PDK — see page 2.",
|
||||
"€70"]
|
||||
- ["Analog pin",
|
||||
"Multiplexed analog pad access for mixed signal designs. Minimum project size of 2 tiles applies.",
|
||||
"€100 <span class=\"t-sub\">/ pin</span>"]
|
||||
- ["Demoboard PCB",
|
||||
"Optional add-on: your packaged chip, an RP2350 demoboard and a breakout board.",
|
||||
"€100 <span class=\"t-sub\">first 80 boards for individuals are subsidised</span><br>€300 <span class=\"t-sub\">academic & industry</span>"]
|
||||
footnote: >-
|
||||
<b>Silicon area and the demoboard are billed separately.</b> Buying area gets
|
||||
your design manufactured on the wafer — on its own it does not get you a
|
||||
physical chip. To hold your chip in your hand, add the demoboard PCB. Confirm
|
||||
current figures at
|
||||
<b><a href="https://app.tinytapeout.com/calculator">app.tinytapeout.com/calculator</a></b>.
|
||||
|
||||
faq:
|
||||
heading: Frequently asked Questions
|
||||
note: FULL FAQ AT TINYTAPEOUT.COM/FAQ
|
||||
items:
|
||||
- q: How long until I get my chip?
|
||||
a: >-
|
||||
Fabrication takes 6–9 months, then boards are assembled, tested and
|
||||
shipped. Check <a href="https://app.tinytapeout.com/chips">tinytapeout.com/chips</a> for the schedule.</b>.
|
||||
- q: Do I need chip design experience?
|
||||
a: >-
|
||||
No. Getting started documentation on the website and help on the Discord community helps beginners get started.
|
||||
Thousands of past projects are public to learn from.
|
||||
- q: What do I actually receive?
|
||||
a: >-
|
||||
Area alone gets your design onto the wafer. Add the demoboard to receive a
|
||||
packaged chip, an RP2350 demoboard and a breakout board. Bare chips are not available separately.
|
||||
- q: Which processes can I use?
|
||||
a: >-
|
||||
SkyWater SKY130 (130 nm), IHP sg13g2 (130 nm BiCMOS) and GlobalFoundries
|
||||
gf180mcu (180 nm), each on its own shuttle schedule.
|
||||
- q: Is it only open to individuals?
|
||||
a: >-
|
||||
No. Universities, schools and companies run group submissions, and dozens
|
||||
of institutions already teach with Tiny Tapeout.
|
||||
- q: What are the licence terms?
|
||||
a: >-
|
||||
Every design is published publicly under Apache-2.0. The minimum
|
||||
submission is GDS + LEF, produced with any toolchain you like.
|
||||
|
||||
institutions:
|
||||
label: Taught and used at
|
||||
items:
|
||||
- Carnegie Mellon University
|
||||
- New York University
|
||||
- UC Santa Cruz
|
||||
- UC San Diego
|
||||
- San Jose State University
|
||||
- Oklahoma State University
|
||||
- Technical University of Denmark
|
||||
- Linköping University
|
||||
- Graz University of Technology
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# PAGE 2
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
process:
|
||||
heading: Process & fabrication
|
||||
note: TILE DIMENSIONS PER PDK
|
||||
columns:
|
||||
- {label: PDK, width: "19%", style: name}
|
||||
- {label: Foundry, width: "21%"}
|
||||
- {label: Node, width: "17%", style: num}
|
||||
- {label: 1×1 tile area, width: "25%", style: mono}
|
||||
- {label: Package}
|
||||
rows:
|
||||
- ["SKY130A", "SkyWater", "130 nm", "161.00 × 111.52 µm", "QFN-64"]
|
||||
- ["ihp-sg13g2", "IHP", "130 nm BiCMOS", "202.08 × 154.98 µm", "QFN-64"]
|
||||
- ["gf180mcuD", "GlobalFoundries", "180 nm", "346.64 × 160.72 µm", "QFN-64"]
|
||||
footnote: >-
|
||||
One tile holds approximately <b>1,000 standard cells</b>. Larger designs are
|
||||
built from multi-tile blocks from 1×2 up to 8×4; the available sizes differ
|
||||
per PDK. Analog projects require a minimum height of 2 tiles.
|
||||
|
||||
ratings:
|
||||
heading: Absolute maximum ratings
|
||||
note: DIGITAL I/O
|
||||
columns:
|
||||
- {label: Parameter, width: "40%", style: name}
|
||||
- {label: Min, width: "13%", style: num}
|
||||
- {label: Typ, width: "13%", style: num}
|
||||
- {label: Max, width: "13%", style: num}
|
||||
- {label: Unit}
|
||||
rows:
|
||||
- ["I/O supply voltage", "1.71", "3.30", "5.50", "V"]
|
||||
- ["Input frequency", "—", "—", "66", "MHz"]
|
||||
- ["Output toggle frequency", "—", "—", "33", "MHz"]
|
||||
- ["Output drive strength, source/sink", "—", "4", "—", "mA"]
|
||||
- ["Demoboard clock generator", "1", "—", "66.5 M", "Hz"]
|
||||
- ["Pad-to-tile round-trip latency", "—", "—", "20", "ns"]
|
||||
- ["Clock insertion delay, pad to logic", "—", "—", "10", "ns"]
|
||||
- ["Pin-to-pin latency variance", "—", "—", "2", "ns"]
|
||||
footnote: >-
|
||||
Characterised on <b>SKY130A</b> using the <b>sky130_ef_io_gpiov2_pad</b> cell;
|
||||
ratings differ per PDK. Inputs are <b>not 5 V tolerant</b> despite the supply
|
||||
range. Full per-process figures at
|
||||
<b><a href="https://tinytapeout.com/specs/">tinytapeout.com/specs</a></b>.
|
||||
|
||||
gpio:
|
||||
heading: GPIO pin map
|
||||
columns:
|
||||
- {label: Signal, width: "34%", style: mono}
|
||||
- {label: Width, width: "14%", style: num center}
|
||||
- {label: Direction, width: "22%"}
|
||||
- {label: Function}
|
||||
rows:
|
||||
- ["clk", "1", "Input", "Clock"]
|
||||
- ["rst_n", "1", "Input", "Reset, active low"]
|
||||
- ["ui_in[7:0]", "8", "Input", "General purpose"]
|
||||
- ["uo_out[7:0]", "8", "Output", "General purpose"]
|
||||
- ["uio[7:0]", "8", "Bidirectional", "Per-pin direction control"]
|
||||
linkline: >-
|
||||
26 I/O PINS TOTAL ·
|
||||
<b><a href="https://tinytapeout.com/specs/gpio/">TINYTAPEOUT.COM/SPECS/GPIO</a></b>
|
||||
|
||||
analog:
|
||||
heading: Analog I/O
|
||||
note: OPTIONAL
|
||||
columns:
|
||||
- {label: Parameter, style: name}
|
||||
- {label: Value, width: "34%", style: mono}
|
||||
rows:
|
||||
- ["Analog pins, maximum", "6 · ua[0:5]"]
|
||||
- ["Series resistance, pad to project", "< 500 Ω"]
|
||||
- ["Parasitic capacitance", "< 5 pF"]
|
||||
- ["Current per pin, maximum", "4 mA"]
|
||||
- ["VDPWR digital supply", "1.8 V"]
|
||||
- ["VAPWR analog supply", "3.3 V"]
|
||||
linkline: >-
|
||||
ALLOCATED IN ORDER ·
|
||||
<b><a href="https://tinytapeout.com/specs/analog/">TINYTAPEOUT.COM/SPECS/ANALOG</a></b>
|
||||
|
||||
ordering:
|
||||
heading: Ordering information
|
||||
note: APP.TINYTAPEOUT.COM/CALCULATOR
|
||||
headless: true # no header row on this table
|
||||
columns:
|
||||
- {width: "27%", style: name}
|
||||
- {}
|
||||
rows:
|
||||
- ["Shuttle cadence",
|
||||
"Several shuttles per year across the three processes. Check <a href="https://app.tinytapeout.com/chips">tinytapeout.com/chips</a> for the schedule"]
|
||||
- ["Lead time",
|
||||
"6–9 months in fabrication, then assembly, test and fulfilment."]
|
||||
- ["Deliverable",
|
||||
"Silicon area only for remote or shared test, or area plus the demoboard kit: packaged chip, RP2350 demoboard and breakout board."]
|
||||
- ["Design tools",
|
||||
"Supplied open-source LibreLane flow running in GitHub Actions, or any toolchain of your own."]
|
||||
- ["Minimum submission",
|
||||
"GDS + LEF in a public repository, licensed Apache-2.0."]
|
||||
|
||||
disclaimer:
|
||||
label: Disclaimer
|
||||
body: >-
|
||||
Specifications are indicative and subject to change between shuttles.
|
||||
Electrical characteristics are quoted for the SKY130A process unless stated
|
||||
otherwise — consult tinytapeout.com/specs for the process you intend to use.
|
||||
Pricing is indicative; confirm current figures with the calculator before
|
||||
ordering. Tiny Tapeout devices are educational and prototyping parts, and are
|
||||
not qualified for safety-critical, medical or automotive use.
|
||||
@@ -0,0 +1 @@
|
||||
{{#has_footnote}}<p class="tnote">{{&footnote}}</p>{{/has_footnote}}
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg class="bar__logo" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Tiny Tapeout logo">
|
||||
<g transform="matrix(0.75075075,0,0,0.7513148,-156.00601,-72.426747)" fill="#ffffff">
|
||||
<path d="m 341,96.4 c -44.5,0 -83.9,21.9 -108.1,55.5 -7.9,11 -14.2,23.2 -18.5,36.4 h 21.6 52.1 v 90.1 h 39.3 v -24.3 h 22.7 v 87.8 c -3,0.3 -6.1,0.4 -9.2,0.4 -62.2,0 -112.8,-50.6 -112.8,-112.8 0,-10.3 1.4,-20.2 4,-29.6 h -21 c -2.2,9.5 -3.3,19.4 -3.3,29.6 0,73.4 59.7,133.1 133.1,133.1 3.1,0 6.1,-0.1 9.2,-0.3 1.7,-0.1 3.4,-0.3 5.1,-0.5 0.1,0 0.3,0 0.4,0 11.8,-1.3 23.1,-4.1 33.8,-8.3 v 0 c 0,0 0,0 0,0 V 254.1 H 428 V 217.7 H 327.5 V 188.2 H 366 V 151.8 H 259.3 c 20.5,-21.6 49.6,-35.1 81.7,-35.1 62.2,0 112.8,50.6 112.8,112.8 0,40.1 -21,75.4 -52.6,95.4 v 23.4 c 43.3,-22 73,-67 73,-118.8 C 474.1,156.1 414.4,96.4 341,96.4 Z" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 859 B |
@@ -0,0 +1,4 @@
|
||||
<div class="secthead">
|
||||
<h2>{{&heading}}</h2>
|
||||
{{#has_note}}<div class="note">{{¬e}}</div>{{/has_note}}
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
<table class="zebra">
|
||||
<colgroup>{{#columns}}<col{{&width_attr}}>{{/columns}}</colgroup>
|
||||
{{^headless}}
|
||||
<thead><tr>{{#columns}}<th>{{&label}}</th>{{/columns}}</tr></thead>
|
||||
{{/headless}}
|
||||
<tbody>
|
||||
{{#rows}}
|
||||
<tr>{{#cells}}<td class="{{cls}}">{{&v}}</td>{{/cells}}</tr>
|
||||
{{/rows}}
|
||||
</tbody>
|
||||
</table>
|
||||
Reference in New Issue
Block a user