Source and development home for the equipment loan contract generator used by the Brandeis Design and Innovation Design Studio Lab.
The generator is a single self-contained HTML file. BDI staff and student workers fill out a web form, and the page builds a ready-to-sign loan contract PDF in the browser, applying the conditional contract language automatically.
Signed contracts are not stored in this repository, and neither is any generated PDF. They contain borrower personal information and are kept in a BDI staff Google Drive folder:
makerlab.fyi/signed-contracts — the short address staff are pointed at, and the one the generator displays after each download. It resolves to this BDI staff Google Drive folder:
Signed equipment loan contracts (BDI staff only)
Access is managed through Google Drive permissions. If you need access, ask a BDI staff member rather than requesting it through this repository.
-
index.html— the generator. Everything runs from this one file: the form, the equipment catalog, the contract language, and the PDF builder. It is namedindex.htmlbecause GitHub Pages serves that name at the site root. -
Rules.txt— the authoritative spec. Contract wording, form questions, and all six conditional rules. When the spec and the code disagree, this file is what the contract is supposed to say; fix the code to match it. -
DS_Lab_Inventory - Data for contract form.csv— inventory source data: asset ID, contract name, contract category, dimensions, weight in grams, and replacement value for each of the 38 loanable items. The category column drives both the drone rules and the type filter in the form. This file is not the original — see Where the inventory data comes from below.
The BDI letterhead source document is deliberately not in this repository. It embeds a scanned handwritten signature, which must never be committed to a repository that is or may become public. It lives outside the repo, alongside the generated contract PDFs.
-
BDI logo v2 white on blue.png— the logo used in the page header. -
tools/sync-inventory.py— regenerates the generator's equipment catalog from the inventory CSV. See Maintaining the lists below.
Staff do not open this repository. The copy they actually use sits in the Checkout_Contracts folder on the BDI shared Google Drive, alongside the signed contracts and the policy documents.
That Drive folder is treated as read-only from here. Publishing a change is a deliberate manual step: edit and test the HTML in this repository, then copy the finished file over the Drive copy yourself.
Step 1. Open the hosted page (see Hosting below). Nothing to download
or install. Opening index.html from a local copy still works as an offline
fallback.
Step 2. The generator opens on a gate screen asking "Does this person have swipe access to the DS Lab?" The form is not shown until you answer. Yes reveals it. No keeps it hidden and shows a notice pointing the borrower at makerlab.fyi/moodle to complete the training.
Answering again is harmless: a Change the DS Lab access answer link at the bottom of the form returns to the gate, and a part-filled form comes back untouched. The answer is not printed on the contract.
Step 3. Fill in the borrower information and loan details. Contract date and loan start date default to today.
Step 4. Pick the equipment. With 38 items the list is grouped by type, and there are two ways to narrow it:
-
Search by name or asset number. Typing
mavicfinds both Mavic models; typing0083jumps straight to that asset. -
Filter by type using the chips — 3D Scanner, Camera Kit, Charging, Drone, GPS, VR — each showing how many items it holds.
Filtering only hides rows, so anything you have already checked stays checked and still lands on the contract. The recap above the list always shows every selected item, its quantity, the running replacement value, and a count of any selections the current filter is hiding. Remove an item with the × on its chip.
Step 5. Add any additional users who will handle the equipment, then select your own name under contract creator.
Step 6. Click Generate Contract PDF. The file downloads as
BDI_EquipmentLoan_<BorrowerName>_<ContractDate>.pdf.
Step 7. Collect signatures, then file the signed PDF at makerlab.fyi/signed-contracts — the address the page itself shows after a contract downloads.
The instruction appears three times on purpose: in red at the top of the form, in red again above the Generate Contract PDF button, and once more in the download confirmation afterwards. The first two are large (27px) so they read as a warning rather than fine print. The confirmation stays on screen until the next contract is generated or the form is reset — it deliberately does not time out, because it is an action item rather than a status message.
The page loads its PDF library (pdf-lib) from a CDN, so an internet connection
is required to generate a contract.
The generator runs entirely in the browser — it loads no data from a server and
sends nothing anywhere — so it can be served as a plain static page. The one
external request is the pdf-lib script it pulls from a CDN, which means the
page needs an internet connection to build a PDF.
To publish it on GitHub Pages: in the repository settings open Pages, set
Source to Deploy from a branch, pick branch main and folder / (root),
and save. The site appears at https://<owner>.github.io/<repo>/ within a
minute or two. .nojekyll is committed so Pages serves the files as-is instead
of running them through Jekyll.
Note that a GitHub Pages site is public. Pages on a private repository
requires a paid plan, and even then the published site is world-readable —
access-controlled Pages is a GitHub Enterprise Cloud feature. So anything in
this repository, including the inventory and its replacement values, is readable
by anyone who finds the URL. That is why no signature image is stored here any
more; see rule 7 in Rules.txt.
Once the page is hosted, the copy on the shared Drive is redundant. Either retire it or keep it as a deliberate offline fallback, but do not leave a stale copy in circulation — staff following an old bookmark would generate contracts from an out-of-date equipment list.
Six rules change what appears in the finished contract. Rules.txt is the full
statement of each; in brief:
-
Drone dimensions and weight. Drone items print dimensions in inches and weight in grams, because borrowers need the weight to apply for insurance. Custom builds — CineKing 4K Micro, Cinewhoop, DIY Racing/Freestyle — have no authoritative weight, so they print dimensions only. Any inventory item with a blank weight field must omit the weight line.
-
Out-of-Massachusetts travel. A primary location of "Other" whose text does not mention MA, Massachusetts, or Waltham adds transport permission and carry-on luggage language.
-
Drone clauses. A drone in the loan appends the licenses and permits acknowledgement, the liability disclaimer, and — only when additional users are named — an acknowledgement listing them.
-
Department chair approval. A chair certification paragraph and second signature block appear when the loan includes the Artec scanner, or when the borrower is an undergraduate or graduate student and the total replacement value reaches $1,000 or more.
-
Signature block appearance. Both signature blocks render as thin horizontal lines with small captions beneath, never as filled boxes, and stay empty so the borrower fills them in.
-
Creator name order. The dropdown lists names as "Last, First" for alphabetical scanning, but the contract footer must print "First Last", with middle initials preserved in the middle.
The inventory lives in the internal DS Lab inventory Google Sheet, which is the system of record for the lab's equipment. That workbook has a tab dedicated to the contract generator, holding just the columns this tool needs in the order it expects them.
The chain is:
DS Lab inventory Google Sheet (contract-generator tab)
→ exported as an Excel file
→ saved into this repository as DS_Lab_Inventory - Data for contract form.csv
→ tools/sync-inventory.py rebuilds the catalog inside index.html
Two consequences worth keeping in mind:
-
Fix data in the Google Sheet, not in the CSV or the HTML. Anything corrected further down the chain is silently undone by the next export. The CSV in this repository is a snapshot, not the master copy.
-
The sheet is internal and stays internal. Only the exported columns reach this public repository, so keep anything not meant to be public — donor names, purchase records, serial numbers, storage locations — out of the contract-generator tab.
The equipment catalog exists in two places: the CSV in this repository, and
the const INVENTORY array near the top of the <script> block in the HTML. The
running page only reads the array, so editing the sheet alone changes nothing.
Rather than hand-editing the array, export the contract-generator tab from the Google Sheet, save it over the CSV in this repository, and run:
python tools/sync-inventory.py
That rebuilds the array from the sheet, prints a per-category count, and warns
about duplicate asset IDs or two items sharing a printed contract name. Use
--check to report drift without writing (it exits non-zero when the HTML is
stale). Chair-approval flags live in CHAIR_IDS at the top of that script,
because the sheet has no column for them. Both are currently in sync at 38 items across six
categories: 3D Scanner (6), Camera Kit (3), Charging (1), Drone (14), GPS (1),
VR (13).
Each catalog entry carries an assetId (the sheet's zero-padded ID, shown in the
form and searchable) and a category taken verbatim from the sheet's Contract
Category column. Category strings feed the type filter and the drone rules, so
spelling matters: drone detection matches the word "drone" case-insensitively.
Adding a new category to the sheet automatically adds a filter chip — no code
change needed.
Also in that script block:
-
Staff list (
STAFF) — the names offered in the contract creator dropdown. Add and remove people as the lab's staff and student workers change. Entries are "Last, First". -
Approval threshold (
STUDENT_LOAN_THRESHOLD) — currently1000. The dollar amount that triggers department chair approval for student loans. Because the threshold is measured against replacement values, keep those values current in both the CSV and the HTML catalog. -
Chair approval flag (
requiresChairApproval) — set on the Artec scanner. Add it to any future item that should always require a chair signature.
tools/sync-inventory.py warns about the two data problems that actually bite:
a duplicated asset ID, and two items sharing a printed contract name. Both were
present earlier and are now resolved — the duplicate 0067 row was removed from
the sheet, and asset 0008 was renamed from "Oculus Rift" to "Oculus Rift S" to
distinguish it from 0001. A clean run prints no warnings, so treat any warning
as something to fix in the sheet rather than in code.
Two quirks the import absorbs silently, so they need no action:
-
IDs
85and86arrive without leading zeros; they are re-padded to0085and0086to match the rest of the catalog. -
Trailing spaces in names and dollar amounts are trimmed, and values like
"8,999.00"or a missing$parse correctly.
Contract names print on a signed legal document, so the script never invents or alters one — it only reports collisions. Renaming an item is a deliberate edit to the sheet.
The policy and instruction documents that accompany this generator live in the Drive folder with the signed contracts:
-
BDI Equipment Loan Policies and Procedures
-
Loan Contract Generator Instructions