feat: Initial ZK-Glasses project — IR anti-surveillance eyewear

Complete hardware design for glasses with flush-mounted 940nm IR LEDs
that are invisible to human eyes but overwhelm camera sensors:

- OpenSCAD parametric models (stealth integrated frame + snap-on clip)
- SMD LEDs behind IR-pass filter strips (Wratten 87C style)
- ATtiny85 PWM firmware (6 modes, brightness control, auto-off)
- SVG circuit schematic (dark-themed, full driver circuit)
- 10 rendered preview images (hero, front, cross-section, camera view)
- KiCad project shell for future PCB layout

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-02-21 17:42:21 -07:00
commit 90e1244aa3
18 changed files with 2261 additions and 0 deletions

372
firmware/zk_glasses.ino Normal file
View File

@ -0,0 +1,372 @@
/*
*
* ZK-Glasses ATtiny85 IR LED Controller Firmware
*
* Board: ATtiny85 (ATTinyCore, 8 MHz internal)
* Programmer: USBasp / Arduino as ISP
* License: MIT
*
*
* Pin Assignment (DIP-8):
*
* ATtiny85
* (RST) PB5 1 8 VCC
* (ADC) PB3 2 7 PB2 (BTN)
* (OC1B)PB4 3 6 PB1 (LED_R) OC0B
* GND 4 5 PB0 (LED_L) OC0A
*
*
* PB0 - LED group LEFT (8 IR LEDs via N-MOSFET gate)
* PB1 - LED group RIGHT (8 IR LEDs via N-MOSFET gate)
* PB2 - Tactile button (internal pull-up, active LOW)
* PB3 - Status LED (green, current-limited)
* PB4 - Battery voltage sense (ADC2, voltage divider)
*
* Modes:
* 0 OFF LEDs off, MCU in low-power idle
* 1 CONSTANT Full brightness, steady
* 2 PULSE_30HZ 30 Hz square wave (half power draw)
* 3 PULSE_60HZ 60 Hz, matches common camera fps
* 4 RANDOM_FLICKER Pseudorandom on/off, defeats adaptive filters
* 5 STEALTH 25% duty constant (very low visibility)
*
* Controls:
* Short press (<500ms) Cycle to next mode
* Long press (>800ms) Cycle brightness (255075100%)
* Double press (<300ms) Instant OFF
*
* Features:
* - Auto-off after 2 hours (configurable)
* - Low battery warning: status LED blinks when Vcc < 3.3V
* - All timing via Timer0 (no delay() in main loop)
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
// ── Pin Definitions ──────────────────────────────────────────
#define PIN_LED_L PB0 // Left IR LED group (OC0A)
#define PIN_LED_R PB1 // Right IR LED group (OC0B)
#define PIN_BTN PB2 // Button input
#define PIN_STATUS PB3 // Status LED
#define PIN_VBAT PB4 // Battery ADC (ADC2)
// ── Configuration ────────────────────────────────────────────
#define NUM_MODES 6
#define DEBOUNCE_MS 40
#define SHORT_PRESS_MAX 500 // ms — below this = short press
#define LONG_PRESS_MIN 800 // ms — above this = long press
#define DOUBLE_PRESS_MAX 300 // ms — gap for double-press detection
#define AUTO_OFF_MS 7200000UL // 2 hours in ms
#define LOW_BATT_ADC 175 // ~3.3V via voltage divider (3.3/5*1024*R2/(R1+R2))
#define BATT_CHECK_INTERVAL 10000 // Check battery every 10s
// ── Brightness Levels (PWM duty 0255) ───────────────────────
const uint8_t BRIGHTNESS_LEVELS[] = { 64, 128, 192, 255 };
#define NUM_BRIGHTNESS 4
// ── Mode Enumeration ─────────────────────────────────────────
enum Mode : uint8_t {
MODE_OFF = 0,
MODE_CONSTANT = 1,
MODE_PULSE_30HZ = 2,
MODE_PULSE_60HZ = 3,
MODE_RANDOM = 4,
MODE_STEALTH = 5
};
// ── State ────────────────────────────────────────────────────
volatile uint8_t g_mode = MODE_OFF;
volatile uint8_t g_brightness_idx = 3; // Start at full
volatile uint32_t g_millis = 0;
volatile bool g_btn_pressed = false;
uint32_t g_mode_start_ms = 0; // For auto-off timer
uint32_t g_last_batt_check = 0;
bool g_low_battery = false;
uint16_t g_lfsr = 0xACE1; // LFSR seed for random mode
// ── Millisecond Timer (Timer0 overflow at 8MHz/64/256 ≈ 488Hz) ──
// We'll use Timer1 for millis since Timer0 is used for PWM
// Actually, let's use a simple millis implementation with Timer0
// Timer0 is set up for Fast PWM on OC0A/OC0B
// We'll track time using Timer1 overflow
ISR(TIMER1_OVF_vect) {
// Timer1 at 8MHz/64, 8-bit overflow = every 2.048ms
// We'll count overflows for rough millisecond tracking
g_millis += 2;
}
// ── LFSR Pseudorandom (16-bit Galois) ────────────────────────
uint16_t lfsr_next() {
uint16_t bit = ((g_lfsr >> 0) ^ (g_lfsr >> 2) ^
(g_lfsr >> 3) ^ (g_lfsr >> 5)) & 1u;
g_lfsr = (g_lfsr >> 1) | (bit << 15);
return g_lfsr;
}
// ── ADC Read (blocking, 10-bit) ──────────────────────────────
uint16_t read_adc(uint8_t channel) {
ADMUX = channel; // Vcc reference, selected channel
ADCSRA = (1 << ADEN) | (1 << ADSC) | // Enable, start conversion
(1 << ADPS2) | (1 << ADPS1); // Prescaler /64
while (ADCSRA & (1 << ADSC)); // Wait for completion
uint16_t result = ADC;
ADCSRA &= ~(1 << ADEN); // Disable ADC to save power
return result;
}
// ── Set LED PWM Duty Cycle ───────────────────────────────────
void set_leds(uint8_t duty) {
OCR0A = duty; // Left group
OCR0B = duty; // Right group
}
// ── Status LED Control ───────────────────────────────────────
void status_led(bool on) {
if (on) PORTB |= (1 << PIN_STATUS);
else PORTB &= ~(1 << PIN_STATUS);
}
// ── Button Reading (debounced) ───────────────────────────────
bool button_is_down() {
return !(PINB & (1 << PIN_BTN)); // Active LOW
}
// ── Setup ────────────────────────────────────────────────────
void setup() {
// --- GPIO ---
DDRB = (1 << PIN_LED_L) | (1 << PIN_LED_R) | (1 << PIN_STATUS);
PORTB = (1 << PIN_BTN); // Pull-up on button
// --- Timer0: Fast PWM on OC0A (PB0) and OC0B (PB1) ---
// Mode 3 (Fast PWM, TOP=0xFF), prescaler /1 for ~31.4 kHz base
// Non-inverting output on both channels
TCCR0A = (1 << COM0A1) | (1 << COM0B1) |
(1 << WGM01) | (1 << WGM00);
TCCR0B = (1 << CS00); // No prescaler → 8MHz/256 = 31.25kHz
OCR0A = 0;
OCR0B = 0;
// --- Timer1: Millis tracking ---
// CTC mode, prescaler /64 → overflow at 8MHz/64/256 ≈ 488 Hz
TCCR1 = (1 << CS12) | (1 << CS11) | (1 << CS10); // /64
TIMSK |= (1 << TOIE1); // Overflow interrupt
sei(); // Enable global interrupts
// Startup flash
status_led(true);
_delay_ms(200);
status_led(false);
}
// ── Process Button Input ─────────────────────────────────────
void process_button() {
static uint32_t press_start = 0;
static uint32_t last_release = 0;
static bool was_pressed = false;
static bool awaiting_double = false;
static uint8_t press_count = 0;
bool pressed = button_is_down();
uint32_t now = g_millis;
if (pressed && !was_pressed) {
// --- Button just pressed ---
press_start = now;
was_pressed = true;
}
else if (!pressed && was_pressed) {
// --- Button just released ---
uint32_t duration = now - press_start;
was_pressed = false;
if (duration > LONG_PRESS_MIN) {
// Long press → cycle brightness
g_brightness_idx = (g_brightness_idx + 1) % NUM_BRIGHTNESS;
// Flash status LED to indicate level
for (uint8_t i = 0; i <= g_brightness_idx; i++) {
status_led(true);
_delay_ms(80);
status_led(false);
_delay_ms(80);
}
}
else if (duration < SHORT_PRESS_MAX) {
// Short press — check for double press
if (awaiting_double && (now - last_release < DOUBLE_PRESS_MAX)) {
// Double press → OFF
g_mode = MODE_OFF;
set_leds(0);
awaiting_double = false;
press_count = 0;
status_led(true);
_delay_ms(50);
status_led(false);
return;
}
awaiting_double = true;
last_release = now;
press_count++;
}
}
// Finalize single press after double-press window expires
if (awaiting_double && !pressed &&
(now - last_release > DOUBLE_PRESS_MAX)) {
// Single short press → next mode
g_mode = (g_mode + 1) % NUM_MODES;
g_mode_start_ms = now;
awaiting_double = false;
press_count = 0;
// Quick status flash for mode feedback
for (uint8_t i = 0; i <= g_mode; i++) {
status_led(true);
_delay_ms(40);
status_led(false);
_delay_ms(40);
}
}
}
// ── Battery Check ────────────────────────────────────────────
void check_battery() {
uint16_t adc_val = read_adc(2); // ADC2 = PB4
g_low_battery = (adc_val < LOW_BATT_ADC);
}
// ── Main Loop ────────────────────────────────────────────────
void loop() {
uint32_t now = g_millis;
// --- Button handling ---
process_button();
// --- Auto-off timer ---
if (g_mode != MODE_OFF &&
(now - g_mode_start_ms > AUTO_OFF_MS)) {
g_mode = MODE_OFF;
set_leds(0);
}
// --- Battery check (periodic) ---
if (now - g_last_batt_check > BATT_CHECK_INTERVAL) {
g_last_batt_check = now;
check_battery();
}
// --- Low battery warning ---
if (g_low_battery && g_mode != MODE_OFF) {
// Blink status LED every 2 seconds
status_led((now / 500) % 4 == 0);
}
// --- LED Mode Execution ---
uint8_t duty = BRIGHTNESS_LEVELS[g_brightness_idx];
switch (g_mode) {
case MODE_OFF:
set_leds(0);
status_led(false);
// Could enter sleep mode here for power savings
break;
case MODE_CONSTANT:
set_leds(duty);
break;
case MODE_PULSE_30HZ:
// 30 Hz = 33.3ms period, 16.7ms on / 16.7ms off
if ((now % 33) < 17)
set_leds(duty);
else
set_leds(0);
break;
case MODE_PULSE_60HZ:
// 60 Hz = 16.7ms period, 8.3ms on / 8.3ms off
if ((now % 17) < 9)
set_leds(duty);
else
set_leds(0);
break;
case MODE_RANDOM:
// Change state every 525ms (pseudorandom)
{
static uint32_t next_change = 0;
if (now >= next_change) {
uint16_t rnd = lfsr_next();
// Random on/off
if (rnd & 1)
set_leds(duty);
else
set_leds(0);
// Random interval 525ms
next_change = now + 5 + (rnd % 21);
}
}
break;
case MODE_STEALTH:
// 25% of selected brightness, constant
set_leds(duty / 4);
break;
}
_delay_ms(1); // ~1 kHz loop rate
}
/*
* Build & Flash Notes
*
* Arduino IDE Setup:
* 1. Install ATTinyCore via Board Manager
* URL: http://drazzy.com/package_drazzy.com_index.json
* 2. Board: "ATtiny25/45/85 (No bootloader)"
* 3. Chip: ATtiny85
* 4. Clock: 8 MHz (internal)
* 5. Programmer: USBasp (or "Arduino as ISP")
* 6. Burn Bootloader first (sets fuses)
* 7. Upload with programmer (Ctrl+Shift+U)
*
* PlatformIO (alternative):
* [env:attiny85]
* platform = atmelavr
* board = attiny85
* framework = arduino
* board_build.f_cpu = 8000000L
* upload_protocol = usbasp
*
* Power Consumption (estimated):
* Mode | Avg Draw | Runtime (500mAh)
*
* OFF | ~5 µA | years
* CONSTANT 100% | ~1.6 A | ~18 min
* PULSE 30Hz | ~800 mA | ~37 min
* PULSE 60Hz | ~800 mA | ~37 min
* RANDOM | ~600 mA | ~50 min
* STEALTH | ~400 mA | ~75 min
*
* (16 LEDs × 100mA = 1.6A max; MCU + driver overhead ~5mA)
*
* Wiring Quick Reference:
*
* ATtiny85 Pin 5 (PB0) 1 Q1 Gate (IRLML6344)
* Q1 Drain LED Group L (8× parallel)
* Q1 Source GND
*
* ATtiny85 Pin 6 (PB1) 1 Q2 Gate (IRLML6344)
* Q2 Drain LED Group R (8× parallel)
* Q2 Source GND
*
* ATtiny85 Pin 7 (PB2) Button GND (internal pull-up)
* ATtiny85 Pin 2 (PB3) 330Ω Status LED GND
* ATtiny85 Pin 3 (PB4) Voltage divider (100k/100k) VBAT
*/

257
hardware/clip_on.scad Normal file
View File

@ -0,0 +1,257 @@
// ============================================================
// ZK-Glasses Snap-On IR Clip Module
// Clips onto any existing glasses temple arm
// ============================================================
//
//
// RENDER INSTRUCTIONS
// F5 = Quick preview (colors, transparency)
// F6 = Full render (slow, for STL export)
// F7 = Export STL
//
// Toggle variables below for different views:
// show_beams = IR beam visualization
// show_temple = phantom glasses arm
// exploded = exploded assembly view
// cross_section = cutaway internal view
// show_electronics = ATtiny + MOSFETs + wiring
//
include <common.scad>
// View Toggles
show_beams = true; // Show purple IR beam cones
show_temple = true; // Show transparent phantom glasses arm
exploded = false; // Exploded assembly view
cross_section = false; // Cutaway to show internals
show_electronics = true; // Show ATtiny, MOSFETs, wires
// Glasses Temple Parameters (measure yours!)
temple_w = 5.0; // Width of your glasses temple arm
temple_h = 2.8; // Thickness of temple arm
temple_len = 140; // Length (for phantom display)
// Clip Parameters
clip_len = 52; // Length of main clip body
clip_wall = 2.0; // Shell thickness
clip_tol = 0.4; // Tolerance around temple
grip_lip = 0.6; // Inward lip for snap retention
// LED Array
led_count = 5; // LEDs along top of each clip
led_pitch = 9.0; // Center-to-center spacing
led_dia = 3.0; // 3mm LEDs
led_fwd_tilt = 12; // Forward tilt angle (toward cameras)
led_out_tilt = 5; // Slight outward splay
// Battery Pod
batt_l = 38; // Battery compartment length
batt_w = 22; // Battery compartment width
batt_h = 8; // Battery compartment height
// Bridge Connector
bridge_w = 3.0; // Width of brow connector strip
bridge_h = 2.5; // Height of connector
// Derived
clip_inner_w = temple_w + clip_tol * 2;
clip_inner_h = temple_h + clip_tol * 2;
clip_outer_w = clip_inner_w + clip_wall * 2;
clip_outer_h = clip_inner_h + clip_wall + 5; // extra height above for LEDs
ex = exploded ? 25 : 0; // exploded offset
//
// CLIP BODY main structural piece
//
module clip_body() {
difference() {
// Outer shell rounded block
minkowski() {
cube([clip_len - 2, clip_outer_w - 2, clip_outer_h - 1],
center = true);
sphere(r = 1.0, $fn = 16);
}
// Temple channel (open at bottom for snap-on)
translate([0, 0, -1])
cube([clip_len + 2, clip_inner_w, clip_inner_h + 2],
center = true);
// Bottom slot opening (narrower than channel for snap fit)
translate([0, 0, -(clip_outer_h/2)])
cube([clip_len + 2, clip_inner_w - grip_lip * 2, clip_wall + 2],
center = true);
// LED sockets (angled holes through top)
for (i = [0 : led_count - 1]) {
x = -(led_pitch * (led_count - 1) / 2) + i * led_pitch;
translate([x, 0, clip_outer_h / 2 - 1])
rotate([-led_fwd_tilt, 0, 0])
cylinder(d = led_dia + 0.4, h = 12, $fn = 24);
}
// Wire channel (horizontal bore through body)
translate([0, 0, clip_outer_h / 2 - 3.5])
rotate([0, 90, 0])
cylinder(d = 2.0, h = clip_len + 4, center = true, $fn = 16);
// Wire exit holes at each end
for (sx = [-1, 1])
translate([sx * (clip_len/2 + 0.5), 0, clip_outer_h / 2 - 3.5])
sphere(d = 3.0, $fn = 16);
}
}
//
// BATTERY POD sits behind the ear
//
module battery_pod() {
difference() {
// Outer shell
minkowski() {
cube([batt_l - 3, batt_w - 3, batt_h - 1], center = true);
sphere(r = 1.5, $fn = 16);
}
// Battery cavity
translate([0, 0, 1])
cube([batt_l - 4, batt_w - 4, batt_h], center = true);
// Charge port cutout (USB-C, one end)
translate([-(batt_l/2), 0, 0])
rotate([0, 90, 0])
rounded_rect_extrude(9.5, 3.5, 1.0, 6);
// Wire exit (connects to clip)
translate([batt_l/2, 0, batt_h/2 - 2])
rotate([0, 90, 0])
cylinder(d = 2.5, h = 4, center = true, $fn = 16);
// Slide switch cutout (top)
translate([-8, 0, batt_h/2])
cube([10, 4.5, 4], center = true);
}
}
// Helper for charge port cutout
module rounded_rect_extrude(w, h, r, depth) {
linear_extrude(depth)
offset(r = r) offset(delta = -r)
square([w - 2*r, h - 2*r], center = true);
}
//
// BROW BRIDGE connects left and right clips
//
module brow_bridge(span = 20) {
// Flexible strip that goes across the nose bridge area
color(CLR_FRAME)
difference() {
minkowski() {
cube([span, bridge_w - 1, bridge_h - 0.5], center = true);
sphere(r = 0.5, $fn = 12);
}
// Wire channel
rotate([0, 90, 0])
cylinder(d = 1.5, h = span + 4, center = true, $fn = 12);
}
}
//
// FULL ASSEMBLY single side (mirrored for both)
//
module clip_assembly_side(side = "left") {
mirror_x = (side == "right") ? 1 : 0;
mirror([mirror_x, 0, 0]) {
// Clip body
translate([0, 0, ex])
color(CLR_FRAME)
clip_body();
// LEDs in sockets
for (i = [0 : led_count - 1]) {
x = -(led_pitch * (led_count - 1) / 2) + i * led_pitch;
translate([x, 0, clip_outer_h / 2 - 1 + ex * 1.5])
rotate([-led_fwd_tilt, 0, 0])
ir_led_3mm(show_beam = show_beams);
}
// Battery pod (behind clip)
translate([clip_len/2 + batt_l/2 + 3, 0, -ex * 0.3])
color(CLR_FRAME)
battery_pod();
// Battery inside pod
translate([clip_len/2 + batt_l/2 + 3, 0, 1 - ex * 0.1])
lipo_battery(l = batt_l - 6, w = batt_w - 6, h = batt_h - 4);
// Slide switch
translate([clip_len/2 + batt_l/2 + 3 - 8, 0, batt_h/2 + 0.5 - ex * 0.2])
slide_switch();
// Phantom temple arm
if (show_temple)
translate([20, 0, 0])
phantom_temple(length = temple_len, width = temple_w, height = temple_h);
// Electronics (inside clip body)
if (show_electronics) {
// ATtiny85
translate([10, 0, clip_outer_h / 2 - 5 + ex * 0.8])
rotate([0, 0, 90])
attiny85_dip8();
// MOSFETs
translate([-5, 2, clip_outer_h / 2 - 5 + ex * 0.6])
mosfet_sot23();
translate([-5, -2, clip_outer_h / 2 - 5 + ex * 0.6])
mosfet_sot23();
// Button (on outer face of clip)
translate([-15, clip_outer_w/2 + 1, 0])
rotate([90, 0, 0])
tact_button();
}
}
}
//
// MAIN ASSEMBLY
//
// Left clip
translate([-40, 0, 0])
clip_assembly_side("left");
// Right clip
translate([40, 0, 0])
clip_assembly_side("right");
// Brow bridge connector
translate([0, 0, clip_outer_h / 2 + ex * 0.8])
brow_bridge(span = 60);
// Optional cross section
if (cross_section) {
// Cut away front half to show internals
translate([0, 50, 0])
cube([200, 100, 100], center = true);
}
//
// PRINTABLE PARTS (uncomment one at a time for STL export)
//
// For 3D printing, render each part flat on the build plate:
// !clip_body(); // Print 2×
// !battery_pod(); // Print 2×
// !brow_bridge(span = 60); // Print 1×
// Print settings:
// Material: PETG (flexibility + heat resistance)
// Layer height: 0.16mm
// Infill: 30% gyroid
// Supports: Yes (for LED socket overhangs)
// Wall count: 3
// Brim: Yes (small footprint parts)

355
hardware/common.scad Normal file
View File

@ -0,0 +1,355 @@
// ============================================================
// ZK-Glasses Common Components Library
// Shared modules for clip-on and integrated frame variants
// ============================================================
//
// Usage: include <common.scad>
//
// All dimensions in millimeters.
// Default preview resolution bump to 128 for final render.
$fn = 64;
//
// Color palette (consistent across all files)
//
CLR_FRAME = [0.22, 0.22, 0.24]; // matte charcoal
CLR_LED_BODY = [0.12, 0.08, 0.18, 0.7]; // dark tinted epoxy
CLR_LED_BEAM = [0.55, 0.0, 1.0, 0.06]; // faint purple IR viz
CLR_SILVER = [0.78, 0.78, 0.80];
CLR_GOLD = [0.83, 0.69, 0.22];
CLR_PCB = [0.05, 0.35, 0.12];
CLR_BATTERY = [0.30, 0.50, 0.72];
CLR_RUBBER = [0.15, 0.15, 0.15];
CLR_WIRE_R = [0.7, 0.1, 0.1];
CLR_WIRE_B = [0.1, 0.1, 0.1];
CLR_IR_FILTER= [0.08, 0.04, 0.10, 0.92]; // near-black IR-pass filter
CLR_FLEX_PCB = [0.15, 0.12, 0.02]; // dark gold flex PCB
CLR_SMD_LED = [0.10, 0.10, 0.12]; // tiny dark SMD body
//
// 2D helper rounded rectangle
//
module rounded_rect_2d(w, h, r) {
offset(r = r)
offset(delta = -r)
square([w, h], center = true);
}
//
// SMD IR LED OSRAM SFH 4726AS style
// 940nm, PLCC-2 (3.5 × 2.8 × 1.9 mm)
// Flush-mountable, nearly invisible in frame
//
module ir_led_smd(show_beam = false) {
// Tiny SMD body barely visible
color(CLR_SMD_LED) {
cube([3.5, 2.8, 1.9], center = true);
// Lens window (top face, recessed)
color([0.06, 0.03, 0.08, 0.85])
translate([0, 0, 0.9])
cube([2.8, 2.0, 0.15], center = true);
}
// Solder pads
color(CLR_SILVER) {
translate([-1.4, 0, -0.95])
cube([0.8, 2.0, 0.1], center = true);
translate([ 1.4, 0, -0.95])
cube([0.8, 2.0, 0.1], center = true);
}
// IR beam wider angle than through-hole (±60°)
if (show_beam) {
color([0.55, 0.0, 1.0, 0.04])
translate([0, 0, 1.5])
cylinder(d1 = 2, d2 = 80, h = 60, $fn = 32);
}
}
//
// Flex PCB LED Strip
// Thin flexible circuit with SMD LEDs pre-soldered
// Slides into channel inside the brow bar
//
module flex_pcb_strip(length = 100, led_count = 6, led_pitch = 12) {
// Flex substrate (0.2mm thick, like a ribbon cable)
color(CLR_FLEX_PCB)
cube([length, 4.0, 0.2], center = true);
// Copper traces (decorative)
color([0.72, 0.55, 0.15], 0.3)
for (dy = [-1, 1])
translate([0, dy * 1.2, 0.12])
cube([length - 2, 0.4, 0.04], center = true);
// SMD LEDs on the strip
for (i = [0 : led_count - 1]) {
x = -(led_pitch * (led_count - 1) / 2) + i * led_pitch;
translate([x, 0, 1.05])
ir_led_smd(show_beam = false);
}
// Connector tail (one end)
color(CLR_FLEX_PCB)
translate([length/2 + 5, 0, 0])
cube([12, 3, 0.2], center = true);
// Connector pins
color(CLR_GOLD)
translate([length/2 + 10, 0, 0])
cube([2, 4, 0.8], center = true);
}
//
// IR-Pass Filter Strip
// Looks opaque black to human eyes, but
// transmits 940nm IR light freely.
// (Kodak Wratten 87C equivalent)
//
module ir_filter_strip(length = 100, width = 4.0, thickness = 0.5) {
color(CLR_IR_FILTER)
cube([length, width, thickness], center = true);
}
//
// 3mm Through-Hole IR LED (TSAL6200 style)
//
module ir_led_3mm(show_beam = false) {
// Epoxy body + dome
color(CLR_LED_BODY) {
cylinder(d = 3.0, h = 4.5);
translate([0, 0, 4.5])
sphere(d = 3.0);
// Flange
cylinder(d = 3.6, h = 0.8);
}
// Anode / cathode leads
color(CLR_SILVER) {
translate([ 1.27/2, 0, -6])
cylinder(d = 0.45, h = 6, $fn = 8);
translate([-1.27/2, 0, -6])
cylinder(d = 0.45, h = 6, $fn = 8);
}
// IR beam cone (visual only)
if (show_beam) {
color(CLR_LED_BEAM)
translate([0, 0, 5.5])
cylinder(d1 = 2.5, d2 = 45, h = 70);
}
}
//
// 5mm Through-Hole IR LED
//
module ir_led_5mm(show_beam = false) {
color(CLR_LED_BODY) {
cylinder(d = 5.0, h = 6.0);
translate([0, 0, 6.0])
sphere(d = 5.0);
cylinder(d = 5.8, h = 1.0);
}
color(CLR_SILVER) {
translate([ 1.27, 0, -8])
cylinder(d = 0.45, h = 8, $fn = 8);
translate([-1.27, 0, -8])
cylinder(d = 0.45, h = 8, $fn = 8);
}
if (show_beam) {
color(CLR_LED_BEAM)
translate([0, 0, 7.0])
cylinder(d1 = 4, d2 = 55, h = 80);
}
}
//
// LiPo Battery Cell
//
module lipo_battery(l = 35, w = 20, h = 5.5) {
color(CLR_BATTERY)
minkowski() {
cube([l - 2, w - 2, h - 1], center = true);
sphere(r = 0.5, $fn = 16);
}
// JST connector tab
color(CLR_GOLD)
translate([l/2 + 1, 0, 0])
cube([3, 5, 1.2], center = true);
// Label
color("White")
translate([0, 0, h/2 + 0.01])
linear_extrude(0.1)
text("3.7V 500mAh", size = 2.5,
halign = "center", valign = "center");
}
//
// TP4056 USB-C Charge Board (25 × 14 mm)
//
module tp4056_board() {
// PCB
color(CLR_PCB) {
cube([25.4, 14.2, 1.2], center = true);
// Copper pads (bottom hint)
translate([0, 0, -0.7])
cube([24, 13, 0.05], center = true);
}
// USB-C receptacle
color(CLR_SILVER)
translate([-12.2, 0, 1.0])
minkowski() {
cube([5, 7.5, 2.0], center = true);
sphere(r = 0.3, $fn = 12);
}
// TP4056 IC
color("DimGray")
translate([3, 0, 0.9])
cube([5, 4, 1.2], center = true);
// Inductor
color([0.25, 0.25, 0.25])
translate([9, 0, 1.0])
cylinder(d = 4, h = 2, center = true, $fn = 16);
// Charging LED (red)
color("Red", 0.8)
translate([0, 5.5, 0.8])
cube([1.6, 0.8, 0.6], center = true);
// Done LED (green)
color("Lime", 0.8)
translate([0, -5.5, 0.8])
cube([1.6, 0.8, 0.6], center = true);
}
//
// ATtiny85 DIP-8 Package
//
module attiny85_dip8() {
// Body
color([0.18, 0.18, 0.20]) {
cube([9.6, 6.35, 3.3], center = true);
// Orientation notch
translate([-4.8, 0, 1.65])
rotate([0, 90, 0])
cylinder(d = 2.0, h = 0.5, $fn = 16);
}
// Dot marker
color("White")
translate([-3.5, -2.0, 1.66])
cylinder(d = 0.8, h = 0.05, $fn = 12);
// Pins (4 per side, 2.54 mm pitch)
color(CLR_SILVER)
for (i = [0:3]) {
// Bottom pins
translate([-3.81 + i * 2.54, -3.8, -1.2])
cube([0.5, 1.5, 0.25]);
// Top pins
translate([-3.81 + i * 2.54, 2.3, -1.2])
cube([0.5, 1.5, 0.25]);
}
}
//
// N-MOSFET SOT-23 Package (IRLML6344)
//
module mosfet_sot23() {
color([0.18, 0.18, 0.20])
cube([2.9, 1.6, 1.1], center = true);
color(CLR_SILVER) {
// Gate, Source (bottom side)
translate([-0.95, -1.3, 0])
cube([0.4, 0.8, 0.15], center = true);
translate([ 0.95, -1.3, 0])
cube([0.4, 0.8, 0.15], center = true);
// Drain (top side)
translate([0, 1.3, 0])
cube([0.4, 0.8, 0.15], center = true);
}
}
//
// Tactile Push Button (6 × 6 mm)
//
module tact_button() {
color([0.15, 0.15, 0.17]) {
cube([6, 6, 3.5], center = true);
}
// Button cap
color([0.3, 0.3, 0.32])
translate([0, 0, 2.0])
cylinder(d = 3.5, h = 1.0, $fn = 24);
// Pins
color(CLR_SILVER)
for (dx = [-3.25, 3.25])
for (dy = [-2.25, 2.25])
translate([dx, dy, -2.5])
cube([0.6, 0.6, 1.5], center = true);
}
//
// Slide Switch (8 × 3 mm)
//
module slide_switch() {
color([0.12, 0.12, 0.14])
cube([8.5, 3.6, 3.5], center = true);
// Slider knob
color(CLR_SILVER)
translate([1.5, 0, 2.0])
cube([3, 1.5, 1.2], center = true);
// Pins
color(CLR_SILVER)
for (dx = [-2.54, 0, 2.54])
translate([dx, 0, -2.5])
cylinder(d = 0.8, h = 2, $fn = 8);
}
//
// Wire Channel (hull between point list)
//
module wire_channel(pts, d = 1.5) {
for (i = [0 : len(pts) - 2])
hull() {
translate(pts[i]) sphere(d = d, $fn = 12);
translate(pts[i+1]) sphere(d = d, $fn = 12);
}
}
//
// Nose Pad (soft rubber)
//
module nose_pad() {
color(CLR_RUBBER)
minkowski() {
scale([1, 0.6, 1])
sphere(d = 8, $fn = 24);
cube([0.5, 0.5, 0.5], center = true);
}
}
//
// Barrel Hinge (5-barrel, 2.5 mm pin)
//
module barrel_hinge(open_angle = 0) {
barrel_d = 3.0;
barrel_h = 2.8;
pin_d = 1.2;
color(CLR_SILVER) {
// 5 interlocking barrels
for (i = [0:4])
translate([0, 0, i * barrel_h])
cylinder(d = barrel_d, h = barrel_h - 0.2, $fn = 20);
// Pin
translate([0, 0, -0.5])
cylinder(d = pin_d, h = 5 * barrel_h + 1, $fn = 12);
}
}
//
// Quick phantom glasses temple (for context)
//
module phantom_temple(length = 140, width = 5, height = 2.5) {
color([0.6, 0.6, 0.65], 0.3) {
// Straight section
cube([length, width, height], center = true);
// Ear hook curve
translate([length/2, 0, 0])
rotate([0, -25, 0])
cube([30, width, height], center = true);
}
}

View File

@ -0,0 +1,574 @@
// ============================================================
// ZK-Glasses Stealth Integrated IR Frame
// Flush-mounted SMD LEDs behind IR-pass filter strips
// Looks like normal glasses invisible except to cameras
// ============================================================
//
// Design philosophy:
// Like Meta Ray-Ban cameras tiny components hidden in
// the frame's natural geometry. A thin IR-pass filter strip
// runs along the brow bar, looking like a decorative dark
// accent line. Behind it: SMD IR LEDs on a flex PCB.
//
//
// F5 = Preview (fast, with colors + beams)
// F6 = Render (slow, for STL export)
// Customizer panel for real-time parameter tweaks
//
include <common.scad>
//
// VIEW CONTROLS
//
/* [View] */
show_beams = true; // IR beam visualization (camera view)
show_filter = true; // IR-pass filter strip overlay
show_flex_pcb = true; // Internal flex PCB + SMD LEDs
show_internals = true; // Battery, MCU, etc.
cross_section = false; // Cutaway showing internal channels
exploded = false; // Exploded assembly view
print_layout = false; // Flat print-ready parts
camera_view = false; // Simulate how a camera sees it (bright beams)
//
// FACE MEASUREMENTS
//
/* [Face Dimensions] */
face_width = 142; // Total frame width
lens_width = 50; // Lens opening width
lens_height = 36; // Lens opening height
lens_corner_r = 9; // Corner radius ( = rounder)
bridge_gap = 18; // Nose bridge gap
nose_bridge_drop = 5; // Bridge drop below lens center
/* [Temple Arms] */
temple_length = 140; // Temple arm length
temple_width = 5.5; // Temple width
temple_thickness = 4.0; // Temple thickness
temple_angle = 8; // Outward splay
ear_bend_angle = 22; // Ear hook curl
ear_bend_start = 108; // Where bend begins
//
// FRAME STRUCTURE
//
/* [Frame] */
brow_thickness = 8.0; // Brow bar height (houses LED channel)
rim_thickness = 3.5; // Lower/side rim
frame_depth = 7.0; // Front-to-back depth
frame_fillet = 1.2; // Edge rounding
//
// STEALTH LED CONFIGURATION
//
/* [IR LEDs (Stealth)] */
led_count_brow = 4; // SMD LEDs per side along brow
led_count_bridge = 1; // Bridge LED (0 or 1)
led_count_temple = 2; // LEDs per temple arm
led_pitch = 10.0; // Brow LED center-to-center
temple_led_pitch = 8.0; // Temple LED spacing
// Filter strip dimensions
filter_width = 3.5; // Height of the IR filter window
filter_depth = 0.6; // Filter material thickness
filter_recess = 0.3; // How deep filter sits into frame
// Internal LED channel
channel_height = 4.5; // Internal cavity height
channel_depth = 5.0; // Internal cavity depth
//
// BATTERY & ELECTRONICS
//
/* [Battery] */
batt_length = 30;
batt_width = 10;
batt_thickness = 4.0;
// Derived
total_leds = (led_count_brow + led_count_temple) * 2 + led_count_bridge;
half_bridge = bridge_gap / 2;
lens_cx = half_bridge + lens_width / 2;
brow_y = lens_height / 2 + brow_thickness / 2;
filter_y = lens_height / 2 + brow_thickness * 0.35; // centered in brow
ex = exploded ? 30 : 0;
// Total brow LED span (for filter strip length)
brow_led_span = led_pitch * (led_count_brow - 1);
filter_length_side = brow_led_span + led_pitch; // per side
filter_length_total = face_width - 12; // nearly full width
//
// FRAME FRONT 2D profile
//
module frame_front_2d() {
difference() {
union() {
// Left lens surround
translate([-lens_cx, 0])
offset(r = rim_thickness)
rounded_rect_2d(lens_width, lens_height, lens_corner_r);
// Right lens surround
translate([lens_cx, 0])
offset(r = rim_thickness)
rounded_rect_2d(lens_width, lens_height, lens_corner_r);
// Bridge
translate([0, lens_height/2 - nose_bridge_drop])
square([bridge_gap + rim_thickness * 1.5, rim_thickness * 2],
center = true);
// Thickened brow bar the key structural element
translate([0, lens_height/2 + brow_thickness/2 - 0.5])
square([face_width + 2, brow_thickness], center = true);
}
// Lens openings
translate([-lens_cx, 0])
rounded_rect_2d(lens_width, lens_height, lens_corner_r);
translate([lens_cx, 0])
rounded_rect_2d(lens_width, lens_height, lens_corner_r);
}
}
//
// FRAME FRONT 3D with LED channels and filter slots
//
module frame_front_3d() {
color(CLR_FRAME)
difference() {
// Base frame shape
minkowski() {
linear_extrude(height = frame_depth - frame_fillet * 2,
center = true)
offset(delta = -frame_fillet)
frame_front_2d();
sphere(r = frame_fillet, $fn = 16);
}
// Filter slot (front face)
// A narrow horizontal groove across the brow bar front
// The IR filter strip press-fits into this slot
translate([0, filter_y, frame_depth/2 - filter_recess])
cube([filter_length_total, filter_width, filter_depth * 2],
center = true);
// Internal LED channel
// Runs the full width of brow bar, behind the filter slot
// Houses the flex PCB strip with SMD LEDs
translate([0, filter_y, 0])
cube([filter_length_total - 4, channel_height, channel_depth],
center = true);
// Wire channels from brow to temples
for (sx = [-1, 1])
translate([sx * (face_width/2 - 2), filter_y, 0])
rotate([0, 90, 0])
cylinder(d = 2.2, h = 15, center = true, $fn = 16);
// Temple LED slots (near hinges)
for (sx = [-1, 1])
for (i = [0 : led_count_temple - 1]) {
tx = sx * (face_width/2 + 2 + i * temple_led_pitch);
translate([tx, 0, frame_depth/2 - filter_recess])
cube([3.8, 3.2, filter_depth * 2], center = true);
// Cavity behind
translate([tx, 0, 0])
cube([4.5, 4.0, channel_depth], center = true);
}
// Bridge LED slot
if (led_count_bridge > 0)
translate([0, lens_height/2 - nose_bridge_drop,
frame_depth/2 - filter_recess]) {
cube([3.8, 3.2, filter_depth * 2], center = true);
translate([0, 0, -channel_depth/2])
cube([4.5, 4.0, channel_depth], center = true);
}
// Flex PCB insertion slot (side of brow bar)
// The strip slides in from the temple end
for (sx = [-1, 1])
translate([sx * (filter_length_total/2 + 1), filter_y, 0])
cube([4, 4.5, 1.0], center = true);
}
}
//
// IR-PASS FILTER STRIPS the stealth magic
// Looks like a subtle dark accent line on the frame
// Actually transmits 940nm IR while blocking visible light
//
module filter_strips() {
// Main brow bar filter continuous strip
translate([0, filter_y, frame_depth/2 - filter_recess/2])
ir_filter_strip(
length = filter_length_total - 1,
width = filter_width - 0.2,
thickness = filter_depth
);
// Temple LED filters (small individual pieces)
for (sx = [-1, 1])
for (i = [0 : led_count_temple - 1]) {
tx = sx * (face_width/2 + 2 + i * temple_led_pitch);
translate([tx, 0, frame_depth/2 - filter_recess/2])
ir_filter_strip(length = 3.4, width = 2.8,
thickness = filter_depth);
}
// Bridge filter
if (led_count_bridge > 0)
translate([0, lens_height/2 - nose_bridge_drop,
frame_depth/2 - filter_recess/2])
ir_filter_strip(length = 3.4, width = 2.8,
thickness = filter_depth);
}
//
// FLEX PCB + SMD LEDs hidden inside the brow bar
//
module internal_led_assembly() {
// Left brow flex strip
translate([-(half_bridge + filter_length_side/2 + 4),
filter_y, 0])
rotate([0, 0, 0])
flex_pcb_strip(
length = filter_length_side + 4,
led_count = led_count_brow,
led_pitch = led_pitch
);
// Right brow flex strip
translate([(half_bridge + filter_length_side/2 + 4),
filter_y, 0])
rotate([0, 0, 0])
flex_pcb_strip(
length = filter_length_side + 4,
led_count = led_count_brow,
led_pitch = led_pitch
);
// Bridge LED (single SMD)
if (led_count_bridge > 0)
translate([0, lens_height/2 - nose_bridge_drop, 0])
ir_led_smd(show_beam = false);
// Temple LEDs
for (sx = [-1, 1])
for (i = [0 : led_count_temple - 1]) {
tx = sx * (face_width/2 + 2 + i * temple_led_pitch);
translate([tx, 0, 0])
ir_led_smd(show_beam = false);
}
}
//
// IR BEAM VISUALIZATION what cameras see
//
module ir_beams() {
beam_alpha = camera_view ? 0.12 : 0.04;
beam_color = camera_view
? [1.0, 1.0, 1.0, 0.15] // white bloom (camera saturated)
: [0.55, 0.0, 1.0, beam_alpha]; // faint purple
// Brow bar beams wide wash from the filter strip
for (sx = [-1, 1])
for (i = [0 : led_count_brow - 1]) {
x = sx * (half_bridge + 8 + i * led_pitch);
translate([x, filter_y, frame_depth/2])
color(beam_color)
// Wide angle SMD beam (±60°)
cylinder(d1 = filter_width, d2 = 90, h = 70, $fn = 24);
}
// Bridge beam
if (led_count_bridge > 0)
translate([0, lens_height/2 - nose_bridge_drop, frame_depth/2])
color(beam_color)
cylinder(d1 = 3, d2 = 60, h = 50, $fn = 24);
// Temple beams
for (sx = [-1, 1])
for (i = [0 : led_count_temple - 1]) {
tx = sx * (face_width/2 + 2 + i * temple_led_pitch);
translate([tx, 0, frame_depth/2])
color(beam_color)
cylinder(d1 = 3, d2 = 50, h = 45, $fn = 24);
}
}
//
// NOSE BRIDGE
//
module nose_assembly() {
for (sx = [-1, 1]) {
color(CLR_SILVER)
translate([sx * 5, -lens_height/2 + nose_bridge_drop, 0])
rotate([20, 0, sx * 15])
cylinder(d = 1.2, h = 14, $fn = 12);
translate([sx * 7, -lens_height/2 + nose_bridge_drop - 10,
frame_depth/2 + 2])
rotate([30, sx * 10, 0])
nose_pad();
}
}
//
// TEMPLE ARM clean with hidden wire channel
//
module temple_arm() {
color(CLR_FRAME)
difference() {
union() {
// Main section
minkowski() {
cube([ear_bend_start - 2,
temple_width - 1, temple_thickness - 0.5],
center = true);
sphere(r = 0.5, $fn = 12);
}
// Ear bend
translate([ear_bend_start/2, 0, 0])
rotate([0, ear_bend_angle, 0])
translate([(temple_length - ear_bend_start)/2, 0, 0])
minkowski() {
cube([temple_length - ear_bend_start - 2,
temple_width - 1,
temple_thickness - 0.5],
center = true);
sphere(r = 0.5, $fn = 12);
}
// Battery bulge (subtle thickening at tip)
translate([ear_bend_start/2, 0, 0])
rotate([0, ear_bend_angle, 0])
translate([(temple_length - ear_bend_start)/2 + 5,
0, 0])
minkowski() {
cube([batt_length + 2, batt_width + 1,
batt_thickness], center = true);
sphere(r = 1.0, $fn = 12);
}
}
// Wire channel (full length)
rotate([0, 90, 0])
cylinder(d = 1.8, h = ear_bend_start + 10,
center = true, $fn = 12);
// Battery cavity
translate([ear_bend_start/2, 0, 0])
rotate([0, ear_bend_angle, 0])
translate([(temple_length - ear_bend_start)/2 + 5,
0, 0.5])
cube([batt_length - 2, batt_width - 2,
batt_thickness - 0.5], center = true);
// Charge port (bottom of battery area, very discreet)
translate([ear_bend_start/2, 0, 0])
rotate([0, ear_bend_angle, 0])
translate([(temple_length - ear_bend_start)/2 + 5,
0, -(batt_thickness/2 + 1)])
cube([9, 3.2, 4], center = true);
// Button recess (tiny, inner face of temple)
translate([5, -(temple_width/2 + 0.5), 0])
cube([4, 2, 2.5], center = true);
}
}
//
// HINGE
//
module hinge_block() {
color(CLR_FRAME)
difference() {
minkowski() {
cube([8, 4, frame_depth - 1], center = true);
sphere(r = 0.5, $fn = 12);
}
cylinder(d = 1.5, h = frame_depth + 2,
center = true, $fn = 16);
}
color(CLR_SILVER)
cylinder(d = 1.2, h = frame_depth + 1,
center = true, $fn = 12);
}
//
// TEMPLE INTERNALS
//
module temple_electronics() {
// Battery
tip_x = ear_bend_start/2;
translate([tip_x, 0, 0])
rotate([0, ear_bend_angle, 0])
translate([(temple_length - ear_bend_start)/2 + 5, 0, 1])
rotate([0, 0, 90])
lipo_battery(l = batt_length - 4,
w = batt_width - 4,
h = batt_thickness - 1.5);
// Tiny MCU (one temple only)
translate([15, 0, 0.5])
scale(0.5)
attiny85_dip8();
}
//
// FULL ASSEMBLY
//
module full_assembly() {
// Frame front
translate([0, 0, ex * 0.3])
frame_front_3d();
// IR-pass filter strips
if (show_filter)
translate([0, 0, ex * 0.5])
filter_strips();
// Internal flex PCB + SMD LEDs
if (show_flex_pcb)
translate([0, 0, ex * 0.15])
internal_led_assembly();
// IR beams
if (show_beams)
translate([0, 0, ex * 0.5])
ir_beams();
// Nose pads
nose_assembly();
// Hinges + Temples
for (side = [-1, 1]) {
hinge_x = side * (face_width / 2 + 2);
translate([hinge_x, 0, 0])
hinge_block();
translate([hinge_x + side * ear_bend_start / 2,
0, -ex * 0.2])
rotate([0, 0, side * temple_angle])
translate([side * 5, 0, 0]) {
temple_arm();
if (show_internals)
temple_electronics();
}
}
}
//
// PRINT LAYOUT
//
module print_parts() {
// Frame front (flat on back)
translate([0, 0, frame_depth/2])
rotate([90, 0, 0])
frame_front_3d();
// Left temple
translate([0, -55, temple_thickness/2])
temple_arm();
// Right temple
translate([0, -75, temple_thickness/2])
temple_arm();
}
//
// RENDER
//
if (print_layout) {
print_parts();
} else if (cross_section) {
difference() {
full_assembly();
// Cut front half to expose LED channel
translate([0, 0, 50 + frame_depth/2 - 1])
cube([300, 300, 100], center = true);
}
} else {
full_assembly();
}
// Info overlay
color("White")
translate([0, -lens_height - 15, 0])
linear_extrude(0.1)
text(str("ZK-Glasses Stealth — ", total_leds,
" SMD IR LEDs @ 940nm"),
size = 3.5, halign = "center",
font = "Liberation Mono");
color("Gray")
translate([0, -lens_height - 22, 0])
linear_extrude(0.1)
text(str("Frame: ", face_width,
"mm | IR filter: Wratten 87C equiv"),
size = 2.8, halign = "center",
font = "Liberation Mono");
color([0.55, 0, 1], 0.4)
translate([0, -lens_height - 28, 0])
linear_extrude(0.1)
text("Invisible to eyes — visible only to cameras",
size = 2.5, halign = "center",
font = "Liberation Mono:style=Italic");
//
// NOTES
//
//
// STEALTH DESIGN:
// The brow bar has a thin horizontal slot cut into its
// front face. An IR-pass filter strip (Kodak Wratten 87C
// or Hoya IR-85) press-fits into this slot. It looks like
// a subtle dark decorative accent line completely normal.
//
// Behind the filter: a flex PCB strip with SMD IR LEDs
// (OSRAM SFH 4726AS or similar, 940nm, PLCC-2 package).
// Each LED is 3.5 × 2.8 × 1.9mm invisible from outside.
//
// The 940nm wavelength is completely invisible to human
// eyes (no red glow), but cameras see bright white spots.
//
// IR-PASS FILTER OPTIONS:
// - Kodak Wratten 87C gel: cheapest, ~$5, can be cut to size
// - Hoya IR-85 glass: durable, optical quality, ~$20
// - Lee 87C polyester: thin, flexible, press-fits easily
// - 3D print in dark PLA, thin enough to pass some IR
//
// ASSEMBLY:
// 1. 3D print frame (PETG, matte black)
// 2. Solder SMD LEDs to flex PCB strip
// 3. Slide flex strip into brow bar channel
// 4. Route wires through temple channels
// 5. Press-fit IR filter strips into front slots
// 6. Insert batteries into temple tips
// 7. Snap in charge port, button, MCU
//
// PRINT SETTINGS:
// Material: PETG matte black (or Nylon PA12)
// Layer: 0.12mm (fine detail for filter slot)
// Infill: 40% gyroid
// Walls: 4 perimeters (structural around channels)
// Supports: Tree, touching buildplate only
// Post: Light sanding, optional soft-touch paint
//
//

BIN
renders/clip_on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
renders/integrated_hero.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
renders/stealth_front.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
renders/stealth_hero.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

BIN
renders/stealth_normal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View File

@ -0,0 +1,612 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1400 900" width="1400" height="900">
<defs>
<style>
text { font-family: 'Courier New', monospace; }
.title { font-size: 18px; fill: #c5c8c6; font-weight: bold; }
.subtitle { font-size: 12px; fill: #969896; }
.ref { font-size: 11px; fill: #b294bb; font-weight: bold; }
.val { font-size: 10px; fill: #81a2be; }
.net { font-size: 10px; fill: #b5bd68; font-weight: bold; }
.pin { font-size: 9px; fill: #969896; }
.wire { stroke: #c5c8c6; stroke-width: 1.5; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.wire-pwr { stroke: #cc6666; stroke-width: 2; fill: none; stroke-linecap: round; }
.wire-gnd { stroke: #969896; stroke-width: 1.5; fill: none; stroke-linecap: round; }
.comp { stroke: #c5c8c6; stroke-width: 1.5; fill: none; }
.comp-fill { stroke: #c5c8c6; stroke-width: 1.5; fill: #282a2e; }
.ic-fill { stroke: #b294bb; stroke-width: 2; fill: #1d1f21; }
.led-fill { stroke: #cc6666; stroke-width: 1.5; fill: rgba(204,102,102,0.15); }
.led-ir { stroke: #b294bb; stroke-width: 1.5; fill: rgba(178,148,187,0.15); }
.mosfet-fill { stroke: #81a2be; stroke-width: 1.5; fill: #1d1f21; }
.cap-fill { stroke: #81a2be; stroke-width: 1.5; fill: none; }
.batt-fill { stroke: #de935f; stroke-width: 2; fill: none; }
.dot { fill: #c5c8c6; }
.gnd-sym { stroke: #969896; stroke-width: 1.5; fill: none; }
.vcc-sym { stroke: #cc6666; stroke-width: 1.5; fill: none; }
.frame { stroke: #373b41; stroke-width: 1; fill: none; }
.section { stroke: #373b41; stroke-width: 0.5; fill: none; stroke-dasharray: 4,4; }
.section-label { font-size: 11px; fill: #5e6266; font-style: italic; }
.beam { fill: url(#irGlow); }
</style>
<linearGradient id="irGlow" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#b294bb;stop-opacity:0.3" />
<stop offset="100%" style="stop-color:#b294bb;stop-opacity:0" />
</linearGradient>
<marker id="arrowhead" markerWidth="6" markerHeight="4" refX="6" refY="2" orient="auto">
<polygon points="0 0, 6 2, 0 4" fill="#b5bd68"/>
</marker>
</defs>
<!-- Background -->
<rect width="1400" height="900" fill="#1d1f21"/>
<!-- Border frame -->
<rect x="10" y="10" width="1380" height="880" class="frame"/>
<rect x="15" y="15" width="1370" height="870" class="frame"/>
<!-- Title block -->
<rect x="15" y="830" width="1370" height="55" class="frame"/>
<text x="30" y="855" class="title">ZK-GLASSES / IR Anti-Surveillance Eyewear / Driver Circuit</text>
<text x="30" y="875" class="subtitle">ATtiny85 PWM Controller | 16x 940nm IR LEDs | LiPo 3.7V 500mAh | Rev 1.0 | 2026-02-21</text>
<text x="1200" y="855" class="subtitle">Sheet 1/1</text>
<text x="1200" y="875" class="subtitle">zk-glasses.svg</text>
<!-- ═══════════════════════════════════════════════════════ -->
<!-- SECTION: Power Supply (left side) -->
<!-- ═══════════════════════════════════════════════════════ -->
<rect x="25" y="30" width="350" height="380" class="section" rx="8"/>
<text x="35" y="48" class="section-label">POWER SUPPLY</text>
<!-- Battery BT1 -->
<line x1="80" y1="120" x2="80" y2="145" class="batt-fill"/>
<line x1="65" y1="145" x2="95" y2="145" class="batt-fill" stroke-width="3"/>
<line x1="72" y1="155" x2="88" y2="155" class="batt-fill" stroke-width="1.5"/>
<line x1="80" y1="155" x2="80" y2="180" class="batt-fill"/>
<text x="55" y="118" class="ref">BT1</text>
<text x="95" y="150" class="val">LiPo</text>
<text x="95" y="162" class="val">3.7V</text>
<text x="95" y="174" class="val">500mAh</text>
<text x="68" y="138" class="pin">+</text>
<text x="72" y="170" class="pin">-</text>
<!-- GND symbol under battery -->
<line x1="80" y1="180" x2="80" y2="195" class="wire-gnd"/>
<line x1="68" y1="195" x2="92" y2="195" class="gnd-sym"/>
<line x1="72" y1="200" x2="88" y2="200" class="gnd-sym"/>
<line x1="76" y1="205" x2="84" y2="205" class="gnd-sym"/>
<!-- Wire from BT1+ up to switch -->
<line x1="80" y1="120" x2="80" y2="80" class="wire-pwr"/>
<!-- Slide Switch SW2 -->
<line x1="80" y1="80" x2="80" y2="70" class="wire-pwr"/>
<circle cx="80" cy="70" r="3" class="comp" fill="#1d1f21"/>
<line x1="80" y1="67" x2="120" y2="55" class="wire-pwr" stroke-width="2"/>
<circle cx="120" cy="55" r="3" class="comp" fill="#1d1f21"/>
<line x1="120" y1="55" x2="120" y2="50" class="wire-pwr"/>
<text x="55" y="65" class="ref">SW2</text>
<text x="55" y="78" class="val">SPDT</text>
<text x="85" y="90" class="pin">Power</text>
<!-- VCC rail from switch -->
<line x1="120" y1="50" x2="120" y2="40" class="wire-pwr"/>
<!-- VCC symbol -->
<line x1="115" y1="40" x2="125" y2="40" class="vcc-sym"/>
<line x1="120" y1="40" x2="120" y2="33" class="vcc-sym"/>
<text x="128" y="38" class="net">VCC 3.7V</text>
<!-- TP4056 Charge Board -->
<rect x="170" y="80" width="130" height="70" class="ic-fill" rx="4"/>
<text x="200" y="105" class="ref">TP4056</text>
<text x="193" y="120" class="val">USB-C Charger</text>
<text x="197" y="135" class="val">w/ Protection</text>
<!-- TP4056 pins -->
<text x="148" y="95" class="pin">USB+</text>
<line x1="170" y1="92" x2="155" y2="92" class="wire"/>
<text x="148" y="140" class="pin">USB-</text>
<line x1="170" y1="137" x2="155" y2="137" class="wire"/>
<!-- USB-C icon -->
<rect x="130" y="85" width="22" height="14" rx="4" class="comp-fill"/>
<text x="133" y="96" style="font-size:8px;fill:#969896">USB</text>
<line x1="152" y1="92" x2="155" y2="92" class="wire"/>
<!-- TP4056 BAT+ output -->
<line x1="300" y1="92" x2="340" y2="92" class="wire-pwr"/>
<text x="302" y="88" class="pin">BAT+</text>
<line x1="340" y1="92" x2="340" y2="50" class="wire-pwr"/>
<line x1="340" y1="50" x2="120" y2="50" class="wire-pwr"/>
<circle cx="120" cy="50" r="2.5" class="dot"/>
<!-- TP4056 BAT- output -->
<line x1="300" y1="137" x2="340" y2="137" class="wire-gnd"/>
<text x="302" y="133" class="pin">BAT-</text>
<line x1="340" y1="137" x2="340" y2="195" class="wire-gnd"/>
<line x1="328" y1="195" x2="352" y2="195" class="gnd-sym"/>
<line x1="332" y1="200" x2="348" y2="200" class="gnd-sym"/>
<line x1="336" y1="205" x2="344" y2="205" class="gnd-sym"/>
<!-- Charging LED indicators (small) -->
<circle cx="185" y="160" r="3" fill="rgba(204,102,102,0.4)" stroke="#cc6666" stroke-width="1"/>
<text x="192" y="163" style="font-size:8px;fill:#cc6666">CHG</text>
<circle cx="245" y="160" r="3" fill="rgba(181,189,104,0.4)" stroke="#b5bd68" stroke-width="1"/>
<text x="252" y="163" style="font-size:8px;fill:#b5bd68">DONE</text>
<!-- Decoupling cap C1 -->
<line x1="250" y1="50" x2="250" y2="230" class="wire"/>
<circle cx="250" cy="50" r="2.5" class="dot"/>
<line x1="240" y1="228" x2="260" y2="228" class="cap-fill" stroke-width="2"/>
<line x1="240" y1="235" x2="260" y2="235" class="cap-fill" stroke-width="2"/>
<line x1="250" y1="235" x2="250" y2="255" class="wire-gnd"/>
<line x1="238" y1="255" x2="262" y2="255" class="gnd-sym"/>
<line x1="242" y1="260" x2="258" y2="260" class="gnd-sym"/>
<line x1="246" y1="265" x2="254" y2="265" class="gnd-sym"/>
<text x="263" y="225" class="ref">C1</text>
<text x="263" y="238" class="val">100nF</text>
<!-- Voltage Divider for battery sense -->
<text x="35" y="245" class="section-label">BATT SENSE</text>
<!-- R20 top -->
<line x1="80" y1="250" x2="80" y2="265" class="wire"/>
<!-- Resistor body R20 -->
<rect x="72" y="265" width="16" height="40" class="comp-fill" rx="2"/>
<text x="92" y="282" class="ref">R20</text>
<text x="92" y="294" class="val">100k</text>
<!-- Junction between R20 and R21 -->
<line x1="80" y1="305" x2="80" y2="315" class="wire"/>
<circle cx="80" cy="315" r="2.5" class="dot"/>
<!-- Line out to VBAT label -->
<line x1="80" y1="315" x2="130" y2="315" class="wire"/>
<text x="133" y="319" class="net">VBAT_SENSE</text>
<!-- R21 bottom -->
<line x1="80" y1="315" x2="80" y2="325" class="wire"/>
<rect x="72" y="325" width="16" height="40" class="comp-fill" rx="2"/>
<text x="92" y="342" class="ref">R21</text>
<text x="92" y="354" class="val">100k</text>
<line x1="80" y1="365" x2="80" y2="385" class="wire-gnd"/>
<line x1="68" y1="385" x2="92" y2="385" class="gnd-sym"/>
<line x1="72" y1="390" x2="88" y2="390" class="gnd-sym"/>
<line x1="76" y1="395" x2="84" y2="395" class="gnd-sym"/>
<!-- Connect R20 top to VCC -->
<line x1="80" y1="250" x2="80" y2="240" class="wire-pwr"/>
<line x1="80" y1="240" x2="120" y2="240" class="wire-pwr"/>
<line x1="120" y1="240" x2="120" y2="50" class="wire-pwr"/>
<circle cx="120" cy="240" r="2.5" class="dot"/>
<!-- ═══════════════════════════════════════════════════════ -->
<!-- SECTION: Microcontroller (center) -->
<!-- ═══════════════════════════════════════════════════════ -->
<rect x="400" y="30" width="320" height="470" class="section" rx="8"/>
<text x="410" y="48" class="section-label">MICROCONTROLLER</text>
<!-- ATtiny85 IC body -->
<rect x="470" y="120" width="160" height="200" class="ic-fill" rx="6"/>
<!-- IC notch -->
<path d="M 545 120 A 10 10 0 0 1 555 120" class="ic-fill" fill="none"/>
<text x="510" y="175" class="title" style="font-size:16px;fill:#b294bb">ATtiny85</text>
<text x="518" y="195" class="val" style="font-size:11px">DIP-8</text>
<text x="520" y="210" class="val" style="font-size:9px">8MHz int.</text>
<!-- Pin labels (left side: 1-4) -->
<!-- Pin 1: PB5/RESET -->
<line x1="470" y1="155" x2="430" y2="155" class="wire"/>
<text x="475" y="159" class="pin" style="text-anchor:start">PB5</text>
<text x="393" y="159" class="pin">(RST) 1</text>
<!-- Pin 2: PB3 (status LED) -->
<line x1="470" y1="195" x2="430" y2="195" class="wire"/>
<text x="475" y="199" class="pin" style="text-anchor:start">PB3</text>
<text x="410" y="199" class="pin">2</text>
<!-- Pin 3: PB4 (ADC - battery sense) -->
<line x1="470" y1="235" x2="430" y2="235" class="wire"/>
<text x="475" y="239" class="pin" style="text-anchor:start">PB4</text>
<text x="410" y="239" class="pin">3</text>
<!-- Pin 4: GND -->
<line x1="470" y1="275" x2="430" y2="275" class="wire-gnd"/>
<text x="475" y="279" class="pin" style="text-anchor:start">GND</text>
<text x="410" y="279" class="pin">4</text>
<!-- Pin labels (right side: 5-8) -->
<!-- Pin 5: PB0 (LED_L) -->
<line x1="630" y1="275" x2="680" y2="275" class="wire"/>
<text x="620" y="279" class="pin" style="text-anchor:end">PB0</text>
<text x="685" y="279" class="pin">5</text>
<!-- Pin 6: PB1 (LED_R) -->
<line x1="630" y1="235" x2="680" y2="235" class="wire"/>
<text x="620" y="239" class="pin" style="text-anchor:end">PB1</text>
<text x="685" y="239" class="pin">6</text>
<!-- Pin 7: PB2 (Button) -->
<line x1="630" y1="195" x2="680" y2="195" class="wire"/>
<text x="620" y="199" class="pin" style="text-anchor:end">PB2</text>
<text x="685" y="199" class="pin">7</text>
<!-- Pin 8: VCC -->
<line x1="630" y1="155" x2="680" y2="155" class="wire-pwr"/>
<text x="620" y="159" class="pin" style="text-anchor:end">VCC</text>
<text x="685" y="159" class="pin">8</text>
<!-- VCC connection to pin 8 -->
<line x1="680" y1="155" x2="700" y2="155" class="wire-pwr"/>
<line x1="700" y1="155" x2="700" y2="80" class="wire-pwr"/>
<line x1="700" y1="80" x2="340" y2="80" class="wire-pwr"/>
<line x1="340" y1="80" x2="340" y2="50" class="wire-pwr"/>
<circle cx="340" cy="80" r="2.5" class="dot"/>
<text x="705" y="85" class="net">VCC</text>
<!-- GND connection from pin 4 -->
<line x1="430" y1="275" x2="430" y2="310" class="wire-gnd"/>
<line x1="418" y1="310" x2="442" y2="310" class="gnd-sym"/>
<line x1="422" y1="315" x2="438" y2="315" class="gnd-sym"/>
<line x1="426" y1="320" x2="434" y2="320" class="gnd-sym"/>
<!-- RST pullup to VCC -->
<line x1="430" y1="155" x2="430" y2="100" class="wire"/>
<rect x="422" y="100" width="16" height="30" class="comp-fill" rx="2"/>
<line x1="430" y1="100" x2="430" y2="80" class="wire-pwr"/>
<line x1="430" y1="80" x2="340" y2="80" class="wire-pwr"/>
<circle cx="430" cy="80" r="2.5" class="dot"/>
<text x="445" y="112" class="ref">R22</text>
<text x="445" y="124" class="val">10k</text>
<!-- PB3 → Status LED path -->
<line x1="430" y1="195" x2="430" y2="380" class="wire"/>
<!-- R19 resistor -->
<rect x="422" y="380" width="16" height="35" class="comp-fill" rx="2"/>
<text x="445" y="395" class="ref">R19</text>
<text x="445" y="407" class="val">330R</text>
<line x1="430" y1="415" x2="430" y2="430" class="wire"/>
<!-- Status LED -->
<polygon points="420,430 440,430 430,450" class="led-fill" fill="rgba(181,189,104,0.3)"/>
<line x1="420" y1="450" x2="440" y2="450" class="led-fill"/>
<!-- LED arrows -->
<line x1="442" y1="435" x2="450" y2="428" class="wire" stroke="#b5bd68" stroke-width="1"/>
<polygon points="450,428 446,432 449,432" fill="#b5bd68"/>
<line x1="445" y1="440" x2="453" y2="433" class="wire" stroke="#b5bd68" stroke-width="1"/>
<polygon points="453,433 449,437 452,437" fill="#b5bd68"/>
<text x="455" y="443" class="ref">LED1</text>
<text x="455" y="455" class="val">Green</text>
<line x1="430" y1="450" x2="430" y2="470" class="wire-gnd"/>
<line x1="418" y1="470" x2="442" y2="470" class="gnd-sym"/>
<line x1="422" y1="475" x2="438" y2="475" class="gnd-sym"/>
<line x1="426" y1="480" x2="434" y2="480" class="gnd-sym"/>
<!-- PB4 → VBAT_SENSE -->
<line x1="430" y1="235" x2="380" y2="235" class="wire"/>
<line x1="380" y1="235" x2="380" y2="315" class="wire"/>
<line x1="380" y1="315" x2="130" y2="315" class="wire"/>
<circle cx="130" cy="315" r="0" class="dot"/>
<text x="383" y="290" class="net" style="font-size:9px" transform="rotate(-90,383,290)">VBAT_SENSE</text>
<!-- PB2 → Button -->
<line x1="680" y1="195" x2="700" y2="195" class="wire"/>
<line x1="700" y1="195" x2="700" y2="360" class="wire"/>
<!-- Button symbol -->
<circle cx="700" cy="360" r="3" class="comp" fill="#1d1f21"/>
<line x1="700" y1="363" x2="700" y2="375" class="wire"/>
<line x1="690" y1="375" x2="710" y2="375" class="comp"/>
<line x1="688" y1="385" x2="712" y2="385" class="comp"/>
<line x1="700" y1="385" x2="700" y2="400" class="wire"/>
<!-- Push button bridge -->
<line x1="693" y1="370" x2="715" y2="362" class="comp" stroke-width="2"/>
<circle cx="700" cy="400" r="0" class="dot"/>
<line x1="700" y1="400" x2="700" y2="415" class="wire-gnd"/>
<line x1="688" y1="415" x2="712" y2="415" class="gnd-sym"/>
<line x1="692" y1="420" x2="708" y2="420" class="gnd-sym"/>
<line x1="696" y1="425" x2="704" y2="425" class="gnd-sym"/>
<text x="715" y="370" class="ref">SW1</text>
<text x="715" y="383" class="val">Tact</text>
<text x="715" y="396" class="val">6x6mm</text>
<!-- ═══════════════════════════════════════════════════════ -->
<!-- SECTION: LED Drivers (right side) -->
<!-- ═══════════════════════════════════════════════════════ -->
<rect x="740" y="30" width="640" height="790" class="section" rx="8"/>
<text x="750" y="48" class="section-label">IR LED DRIVER — 16x 940nm</text>
<!-- ──── LEFT LED GROUP (PB0 → Q1 → 8 LEDs) ──── -->
<!-- Wire from PB0 to gate resistor R17 -->
<line x1="680" y1="275" x2="780" y2="275" class="wire"/>
<text x="750" y="270" class="net">LED_L</text>
<!-- R17 gate resistor -->
<rect x="780" y="267" width="35" height="16" class="comp-fill" rx="2"/>
<text x="787" y="262" class="ref">R17</text>
<text x="788" y="292" class="val">1k</text>
<!-- Wire to MOSFET Q1 gate -->
<line x1="815" y1="275" x2="845" y2="275" class="wire"/>
<!-- MOSFET Q1 symbol -->
<rect x="845" y="230" width="70" height="90" class="mosfet-fill" rx="4"/>
<text x="860" y="255" class="ref">Q1</text>
<text x="852" y="270" class="val">IRLML6344</text>
<text x="855" y="285" class="val">N-MOSFET</text>
<text x="855" y="300" class="val">SOT-23</text>
<!-- Gate pin -->
<text x="830" y="279" class="pin">G</text>
<!-- Drain pin (top) -->
<line x1="880" y1="230" x2="880" y2="200" class="wire"/>
<text x="885" y="225" class="pin">D</text>
<!-- Source pin (bottom) -->
<line x1="880" y1="320" x2="880" y2="350" class="wire-gnd"/>
<text x="885" y="340" class="pin">S</text>
<line x1="868" y1="350" x2="892" y2="350" class="gnd-sym"/>
<line x1="872" y1="355" x2="888" y2="355" class="gnd-sym"/>
<line x1="876" y1="360" x2="884" y2="360" class="gnd-sym"/>
<!-- VCC rail for LEDs -->
<line x1="880" y1="80" x2="1350" y2="80" class="wire-pwr" stroke-width="2.5"/>
<line x1="700" y1="80" x2="880" y2="80" class="wire-pwr"/>
<circle cx="880" cy="80" r="2.5" class="dot"/>
<text x="1100" y="72" class="net" style="font-size:12px">VCC RAIL (3.7V)</text>
<!-- LEFT LED array (8 LEDs with individual resistors) -->
<!-- LED row at y=100-200, spread across x=790-1060 -->
<g>
<!-- 8 parallel LED+R branches from VCC to Q1 drain -->
<!-- Branch pattern: VCC → R → LED → Q1_Drain -->
<!-- LED L1 -->
<line x1="800" y1="80" x2="800" y2="100" class="wire"/>
<rect x="794" y="100" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="800" y1="125" x2="800" y2="135" class="wire"/>
<polygon points="793,135 807,135 800,152" class="led-ir"/>
<line x1="793" y1="152" x2="807" y2="152" stroke="#b294bb" stroke-width="1.5"/>
<line x1="800" y1="152" x2="800" y2="165" class="wire"/>
<text x="790" y="97" class="pin" style="font-size:7px">R1</text>
<!-- LED L2 -->
<line x1="835" y1="80" x2="835" y2="100" class="wire"/>
<rect x="829" y="100" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="835" y1="125" x2="835" y2="135" class="wire"/>
<polygon points="828,135 842,135 835,152" class="led-ir"/>
<line x1="828" y1="152" x2="842" y2="152" stroke="#b294bb" stroke-width="1.5"/>
<line x1="835" y1="152" x2="835" y2="165" class="wire"/>
<text x="825" y="97" class="pin" style="font-size:7px">R2</text>
<!-- LED L3 -->
<line x1="870" y1="80" x2="870" y2="100" class="wire"/>
<rect x="864" y="100" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="870" y1="125" x2="870" y2="135" class="wire"/>
<polygon points="863,135 877,135 870,152" class="led-ir"/>
<line x1="863" y1="152" x2="877" y2="152" stroke="#b294bb" stroke-width="1.5"/>
<line x1="870" y1="152" x2="870" y2="165" class="wire"/>
<text x="860" y="97" class="pin" style="font-size:7px">R3</text>
<!-- LED L4 -->
<line x1="905" y1="80" x2="905" y2="100" class="wire"/>
<rect x="899" y="100" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="905" y1="125" x2="905" y2="135" class="wire"/>
<polygon points="898,135 912,135 905,152" class="led-ir"/>
<line x1="898" y1="152" x2="912" y2="152" stroke="#b294bb" stroke-width="1.5"/>
<line x1="905" y1="152" x2="905" y2="165" class="wire"/>
<text x="895" y="97" class="pin" style="font-size:7px">R4</text>
<!-- LED L5 -->
<line x1="940" y1="80" x2="940" y2="100" class="wire"/>
<rect x="934" y="100" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="940" y1="125" x2="940" y2="135" class="wire"/>
<polygon points="933,135 947,135 940,152" class="led-ir"/>
<line x1="933" y1="152" x2="947" y2="152" stroke="#b294bb" stroke-width="1.5"/>
<line x1="940" y1="152" x2="940" y2="165" class="wire"/>
<text x="930" y="97" class="pin" style="font-size:7px">R5</text>
<!-- LED L6 -->
<line x1="975" y1="80" x2="975" y2="100" class="wire"/>
<rect x="969" y="100" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="975" y1="125" x2="975" y2="135" class="wire"/>
<polygon points="968,135 982,135 975,152" class="led-ir"/>
<line x1="968" y1="152" x2="982" y2="152" stroke="#b294bb" stroke-width="1.5"/>
<line x1="975" y1="152" x2="975" y2="165" class="wire"/>
<text x="965" y="97" class="pin" style="font-size:7px">R6</text>
<!-- LED L7 -->
<line x1="1010" y1="80" x2="1010" y2="100" class="wire"/>
<rect x="1004" y="100" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="1010" y1="125" x2="1010" y2="135" class="wire"/>
<polygon points="1003,135 1017,135 1010,152" class="led-ir"/>
<line x1="1003" y1="152" x2="1017" y2="152" stroke="#b294bb" stroke-width="1.5"/>
<line x1="1010" y1="152" x2="1010" y2="165" class="wire"/>
<text x="1000" y="97" class="pin" style="font-size:7px">R7</text>
<!-- LED L8 -->
<line x1="1045" y1="80" x2="1045" y2="100" class="wire"/>
<rect x="1039" y="100" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="1045" y1="125" x2="1045" y2="135" class="wire"/>
<polygon points="1038,135 1052,135 1045,152" class="led-ir"/>
<line x1="1038" y1="152" x2="1052" y2="152" stroke="#b294bb" stroke-width="1.5"/>
<line x1="1045" y1="152" x2="1045" y2="165" class="wire"/>
<text x="1035" y="97" class="pin" style="font-size:7px">R8</text>
<!-- Common drain bus connecting all LED cathodes to Q1 drain -->
<line x1="800" y1="165" x2="1045" y2="165" class="wire"/>
<line x1="880" y1="165" x2="880" y2="200" class="wire"/>
<circle cx="880" cy="165" r="2.5" class="dot"/>
<!-- IR emission glow effects (decorative) -->
<ellipse cx="920" cy="100" rx="160" ry="25" class="beam"/>
<!-- Label -->
<text x="800" y="185" class="ref" style="font-size:10px">D1D8: TSAL6200 (940nm, 8× parallel)</text>
<text x="800" y="197" class="val">R1R8: 47R (each: If = (3.7-1.3)/47 = 51mA)</text>
</g>
<!-- ──── RIGHT LED GROUP (PB1 → Q2 → 8 LEDs) ──── -->
<!-- Wire from PB1 to gate resistor R18 -->
<line x1="680" y1="235" x2="720" y2="235" class="wire"/>
<line x1="720" y1="235" x2="720" y2="510" class="wire"/>
<line x1="720" y1="510" x2="780" y2="510" class="wire"/>
<text x="750" y="505" class="net">LED_R</text>
<!-- R18 gate resistor -->
<rect x="780" y="502" width="35" height="16" class="comp-fill" rx="2"/>
<text x="787" y="497" class="ref">R18</text>
<text x="788" y="527" class="val">1k</text>
<!-- Wire to MOSFET Q2 gate -->
<line x1="815" y1="510" x2="845" y2="510" class="wire"/>
<!-- MOSFET Q2 symbol -->
<rect x="845" y="465" width="70" height="90" class="mosfet-fill" rx="4"/>
<text x="860" y="490" class="ref">Q2</text>
<text x="852" y="505" class="val">IRLML6344</text>
<text x="855" y="520" class="val">N-MOSFET</text>
<text x="855" y="535" class="val">SOT-23</text>
<text x="830" y="514" class="pin">G</text>
<line x1="880" y1="465" x2="880" y2="435" class="wire"/>
<text x="885" y="460" class="pin">D</text>
<line x1="880" y1="555" x2="880" y2="585" class="wire-gnd"/>
<text x="885" y="575" class="pin">S</text>
<line x1="868" y1="585" x2="892" y2="585" class="gnd-sym"/>
<line x1="872" y1="590" x2="888" y2="590" class="gnd-sym"/>
<line x1="876" y1="595" x2="884" y2="595" class="gnd-sym"/>
<!-- RIGHT LED array -->
<g>
<!-- VCC taps for right group -->
<line x1="800" y1="80" x2="800" y2="80" class="wire"/>
<!-- LED R1 -->
<line x1="800" y1="335" x2="800" y2="355" class="wire"/>
<rect x="794" y="335" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="800" y1="310" x2="800" y2="335" class="wire-pwr"/>
<line x1="800" y1="355" x2="800" y2="370" class="wire"/>
<polygon points="793,370 807,370 800,387" class="led-ir"/>
<line x1="793" y1="387" x2="807" y2="387" stroke="#b294bb" stroke-width="1.5"/>
<line x1="800" y1="387" x2="800" y2="400" class="wire"/>
<text x="790" y="328" class="pin" style="font-size:7px">R9</text>
<!-- LED R2 -->
<line x1="835" y1="335" x2="835" y2="355" class="wire"/>
<rect x="829" y="335" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="835" y1="310" x2="835" y2="335" class="wire-pwr"/>
<line x1="835" y1="355" x2="835" y2="370" class="wire"/>
<polygon points="828,370 842,370 835,387" class="led-ir"/>
<line x1="828" y1="387" x2="842" y2="387" stroke="#b294bb" stroke-width="1.5"/>
<line x1="835" y1="387" x2="835" y2="400" class="wire"/>
<!-- LED R3 -->
<line x1="870" y1="335" x2="870" y2="355" class="wire"/>
<rect x="864" y="335" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="870" y1="310" x2="870" y2="335" class="wire-pwr"/>
<line x1="870" y1="355" x2="870" y2="370" class="wire"/>
<polygon points="863,370 877,370 870,387" class="led-ir"/>
<line x1="863" y1="387" x2="877" y2="387" stroke="#b294bb" stroke-width="1.5"/>
<line x1="870" y1="387" x2="870" y2="400" class="wire"/>
<!-- LED R4 -->
<line x1="905" y1="335" x2="905" y2="355" class="wire"/>
<rect x="899" y="335" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="905" y1="310" x2="905" y2="335" class="wire-pwr"/>
<line x1="905" y1="355" x2="905" y2="370" class="wire"/>
<polygon points="898,370 912,370 905,387" class="led-ir"/>
<line x1="898" y1="387" x2="912" y2="387" stroke="#b294bb" stroke-width="1.5"/>
<line x1="905" y1="387" x2="905" y2="400" class="wire"/>
<!-- LED R5 -->
<line x1="940" y1="335" x2="940" y2="355" class="wire"/>
<rect x="934" y="335" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="940" y1="310" x2="940" y2="335" class="wire-pwr"/>
<line x1="940" y1="355" x2="940" y2="370" class="wire"/>
<polygon points="933,370 947,370 940,387" class="led-ir"/>
<line x1="933" y1="387" x2="947" y2="387" stroke="#b294bb" stroke-width="1.5"/>
<line x1="940" y1="387" x2="940" y2="400" class="wire"/>
<!-- LED R6 -->
<line x1="975" y1="335" x2="975" y2="355" class="wire"/>
<rect x="969" y="335" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="975" y1="310" x2="975" y2="335" class="wire-pwr"/>
<line x1="975" y1="355" x2="975" y2="370" class="wire"/>
<polygon points="968,370 982,370 975,387" class="led-ir"/>
<line x1="968" y1="387" x2="982" y2="387" stroke="#b294bb" stroke-width="1.5"/>
<line x1="975" y1="387" x2="975" y2="400" class="wire"/>
<!-- LED R7 -->
<line x1="1010" y1="335" x2="1010" y2="355" class="wire"/>
<rect x="1004" y="335" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="1010" y1="310" x2="1010" y2="335" class="wire-pwr"/>
<line x1="1010" y1="355" x2="1010" y2="370" class="wire"/>
<polygon points="1003,370 1017,370 1010,387" class="led-ir"/>
<line x1="1003" y1="387" x2="1017" y2="387" stroke="#b294bb" stroke-width="1.5"/>
<line x1="1010" y1="387" x2="1010" y2="400" class="wire"/>
<!-- LED R8 -->
<line x1="1045" y1="335" x2="1045" y2="355" class="wire"/>
<rect x="1039" y="335" width="12" height="25" class="comp-fill" rx="1.5"/>
<line x1="1045" y1="310" x2="1045" y2="335" class="wire-pwr"/>
<line x1="1045" y1="355" x2="1045" y2="370" class="wire"/>
<polygon points="1038,370 1052,370 1045,387" class="led-ir"/>
<line x1="1038" y1="387" x2="1052" y2="387" stroke="#b294bb" stroke-width="1.5"/>
<line x1="1045" y1="387" x2="1045" y2="400" class="wire"/>
<!-- VCC bus for right group -->
<line x1="800" y1="310" x2="1045" y2="310" class="wire-pwr"/>
<line x1="920" y1="310" x2="920" y2="80" class="wire-pwr"/>
<circle cx="920" cy="80" r="2.5" class="dot"/>
<circle cx="920" cy="310" r="2.5" class="dot"/>
<!-- Common drain bus for right group -->
<line x1="800" y1="400" x2="1045" y2="400" class="wire"/>
<line x1="880" y1="400" x2="880" y2="435" class="wire"/>
<circle cx="880" cy="400" r="2.5" class="dot"/>
<!-- IR glow -->
<ellipse cx="920" cy="335" rx="160" ry="25" class="beam"/>
<!-- Label -->
<text x="800" y="420" class="ref" style="font-size:10px">D9D16: TSAL6200 (940nm, 8× parallel)</text>
<text x="800" y="432" class="val">R9R16: 47R (each: If = 51mA, total group = 408mA)</text>
</g>
<!-- ═══════════════════════════════════════════════════════ -->
<!-- NOTES section (bottom right) -->
<!-- ═══════════════════════════════════════════════════════ -->
<rect x="740" y="610" width="640" height="210" class="section" rx="8"/>
<text x="750" y="628" class="section-label">DESIGN NOTES</text>
<text x="760" y="650" class="val" style="font-size:11px;fill:#c5c8c6">Circuit Summary:</text>
<text x="760" y="668" class="val" style="font-size:10px">
ATtiny85 generates PWM on PB0/PB1 → gates two IRLML6344 N-MOSFETs
</text>
<text x="760" y="683" class="val" style="font-size:10px">
Each MOSFET switches a bank of 8 IR LEDs (940nm) with individual 47R limiters
</text>
<text x="760" y="698" class="val" style="font-size:10px">
Total max draw: 16 × 51mA = 816mA + MCU overhead ≈ 820mA
</text>
<text x="760" y="713" class="val" style="font-size:10px">
Runtime at full power: 500mAh / 820mA ≈ 36 min
</text>
<text x="760" y="728" class="val" style="font-size:10px">
Pulsed modes (30/60Hz, 50% duty) double runtime to ~72 min
</text>
<text x="760" y="755" class="val" style="font-size:11px;fill:#c5c8c6">Component Count:</text>
<text x="760" y="773" class="val" style="font-size:10px">
1× ATtiny85 | 2× IRLML6344 | 16× TSAL6200 | 16× 47R | 3× misc R
</text>
<text x="760" y="788" class="val" style="font-size:10px">
1× 100nF cap | 1× TP4056 module | 1× LiPo 500mAh | 2× switches | 1× status LED
</text>
<text x="760" y="803" class="val" style="font-size:10px;fill:#de935f">
Estimated BOM cost: ~$15 USD (through-hole prototype)
</text>
<!-- Decorative IR wave symbol in corner -->
<g transform="translate(1300,660)" opacity="0.3">
<circle cx="0" cy="0" r="10" stroke="#b294bb" stroke-width="1.5" fill="none"/>
<circle cx="0" cy="0" r="20" stroke="#b294bb" stroke-width="1" fill="none"/>
<circle cx="0" cy="0" r="30" stroke="#b294bb" stroke-width="0.5" fill="none"/>
<text x="-5" y="5" style="font-size:12px;fill:#b294bb;font-weight:bold">IR</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -0,0 +1,85 @@
(kicad_pcb (version 20221018) (generator pcbnew)
(general
(thickness 1.6)
)
(paper "A4")
(title_block
(title "zk-glasses")
(date "2026-02-21")
)
(layers
(0 "F.Cu" signal)
(31 "B.Cu" signal)
(32 "B.Adhes" user "B.Adhesive")
(33 "F.Adhes" user "F.Adhesive")
(34 "B.Paste" user)
(35 "F.Paste" user)
(36 "B.SilkS" user "B.Silkscreen")
(37 "F.SilkS" user "F.Silkscreen")
(38 "B.Mask" user)
(39 "F.Mask" user)
(40 "Dwgs.User" user "User.Drawings")
(41 "Cmts.User" user "User.Comments")
(42 "Eco1.User" user "User.Eco1")
(43 "Eco2.User" user "User.Eco2")
(44 "Edge.Cuts" user)
(45 "Margin" user)
(46 "B.CrtYd" user "B.Courtyard")
(47 "F.CrtYd" user "F.Courtyard")
(48 "B.Fab" user)
(49 "F.Fab" user)
(50 "User.1" user)
(51 "User.2" user)
(52 "User.3" user)
(53 "User.4" user)
(54 "User.5" user)
(55 "User.6" user)
(56 "User.7" user)
(57 "User.8" user)
(58 "User.9" user)
)
(setup
(pad_to_mask_clearance 0)
(pcbplotparams
(layerselection 0x00010fc_ffffffff)
(plot_on_all_layers_selection 0x0000000_00000000)
(disableapertmacros false)
(usegerberextensions false)
(usegerberattributes true)
(usegerberadvancedattributes true)
(creategerberjobfile true)
(dashed_line_dash_ratio 12.000000)
(dashed_line_gap_ratio 3.000000)
(svgprecision 4)
(plotframeref false)
(viasonmask false)
(mode 1)
(useauxorigin false)
(hpglpennumber 1)
(hpglpenspeed 20)
(hpglpendiameter 15.000000)
(dxfpolygonmode true)
(dxfimperialunits true)
(dxfusepcbnewfont true)
(psnegative false)
(psa4output false)
(plotreference true)
(plotvalue true)
(plotinvisibletext false)
(sketchpadsonfab false)
(subtractmaskfromsilk false)
(outputformat 1)
(mirror false)
(drillshape 1)
(scaleselection 1)
(outputdirectory "")
)
)
(net 0 "")
)

View File

@ -0,0 +1,5 @@
{
"board": {
"filename": "zk-glasses.kicad_pcb"
}
}

View File

@ -0,0 +1 @@
(kicad_sch (version 20230121) (generator "KiCAD-MCP-Server"))