Full Width [alt+shift+f] Shortcuts [alt+shift+k]
Sign Up [alt+shift+s] Log In [alt+shift+l]
1

Abandoning the indie hacking dream for now

from Tiny struggles [alt+shift+b] in technology

I’m taking a break from indie-hacking Will I never write a line of indie code again? Obviously not. I love building, sharing and learning. But I am going to stop trying to make profitable indie-businesses for the next couple months or a year. Building things is fun, but marketing a business that has no traction is a grind and a roller coaster. Something that right now I am tired of. No need for a profitable business Right now I don’t need to make money with indie businesses. It’s totally viable for me to just enjoy the ride working full time (or maybe later part time) to achieve financial independence. I have saved enough already for a secure retirement at a typical retirement age and if I was willing to downscale my lifestyle, I would probably never have to work again. But I’m in no rush. I am excited about my full time work, I get paid very well and the environment is very healthy. I feel like in the next year (or more) I have lots of opportunities for personal and professional growth without a need to grind. And if anything changes, e.g. I get a awful boss - guess what, I can change teams or jobs and be alright. I know that “would people pay money for this?” is a great test for a business, but it’s not the game I want to be playing now. I might later. Wanting it all I like to do a lot of things and “I want it all”. I want to have an amazing career, be super skilled in my main job, develop my hobbies, know a lot about unrelated but interesting disciplines (e.g. biology, math, physics, psychology), learn foreign languages, and be very fit and healthy (running, climbing, gym, yoga, meditation), creative and have a thriving social life (amazing friendship, marriage and great family bonds). Also I have a thirst for adventure and traveling. You see where the problem is. Just having a demanding full time job and a part time side hustle could take most of your physical and mental energy, but I want so much more in life and don’t want to make sacrifices in other areas. I...
11th Nov 2022

Stay updated

Get a weekly newsletter with the top 5 articles worth reading every week.

More from Tiny struggles

Implementing SARM on your VLA dataset in practice

1. Motivation: use big video dataset optimally for VLA training In the first part of this series, I explained what is SARM: Stage-Aware Reward Modeling for Long Horizon Robot Manipulation and how it can be used with a challenge such as Stanford Behavior Challenge (1200h of demonstrations over 50 diverse long horizon tasks). To sum up: Our main model for the robot (VLA) is trained on short windows (chunks) of data for which it predicts actions. Our SARM model is used to estimate progress within an episode and evaluates windows. We want to prioritize training on trajectory segments where the robot made meaningful progress toward task completion. In this post I will explain how I actually implemented this in practice. The code is now open on github. The core of the implementation follows closely the original paper. We will cover the following key areas: The design of the model Sequential Multimodal Architecture that utilizes a Global Anchor Frame. Data input shape and preparation Using the model for scoring the episodes Visual Validation of the predicted progress against our Stage-Aware Ground Truth. 2. The SARM Model Implementation See the source here. The model tackles a dual prediction problem: determining which stage of a task is being performed (classification) and how much progress has been made within that stage (regression). SARM provides a principled approach to stage-aware reward modeling by: Leveraging pretrained vision models (CLIP) for robust visual understanding Fusing multimodal information through Transformers Making hierarchical predictions (stage → progress within stage) Handling variable-length sequences efficiently Architecture Overview This architecture is particularly well-suited for tasks that have clear sequential structure and require fine-grained progress estimation within each stage. The SARM model follows a three-part design: Encoders - Process multimodal inputs (visual and proprioceptive) Shared Backbone - A Transformer that fuses information across time and modalities Dual Heads - Separate outputs for stage classification and progress regression Where the symbols are: B - batch size N - sequence size (multiple frames of images/data - more on that later) ┌────────────────────────────────────────────────────────────────────┐│ INPUT LAYER ││ ││ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ││ │ Image Frames │ │ Joint States │ │ Task Index │ ││ │ (B,N,3, │ │ (B,N,256) │ │ (B,) │ ││ │ 224,224) │ │ │ │ │ ││ └──────┬───────┘ └───────┬──────┘ └────────┬─────┘ │└─────────┼─────────────────-┼──────────────────┼────────────────────┘ │ │ │ ▼ ▼ ▼┌─────────────────────────────────────────────────────────────────────┐│ ENCODER LAYER ││ ││ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ││ │ CLIP (ViT) │ │ LayerNorm │ │ Embedding │ ││ │ [Frozen] │ │ + │ │ Layer │ ││ │ ↓ │ │ Linear │ │ │ ││ │ Linear │ │ │ │ │ ││ │ Projection │ │ Projection │ │ │ ││ │ │ │ │ │ │ ││ │ (512→768) │ │ (256→768) │ │ (50→768) │ ││ └──────┬───────┘ └──────┬───────┘ └───────┬──────┘ ││ │ │ │ ││ │ Visual │ State │ Task ││ │ Embeddings │ Embeddings │ Embedding ││ │ (B,N,768) │ (B,N,768) │ (B,1,768) ││ └─────────┬───────┴──────────────────┘ │└───────────────────┼─────────────────────────────────────────────────┘ │ ▼ ┌─────────────────┐ │ Element-wise │ │ Sum │ │ │ │ Visual + State │ │ + Task │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Add Positional │ │ Bias to Frame 0│ └────────┬────────┘ │ │ Combined Embeddings │ (B,N,768) ▼┌────────────────────────────────────────────────────────────────────┐│ TRANSFORMER BACKBONE ││ ││ ┌───────────────────────────────────────────────────────────────┐ ││ │ Transformer Encoder (8 layers) │ ││ │ │ ││ │ ┌─────────────────────────────────────────────────────────┐ │ ││ │ │ Multi-Head Self-Attention (12 heads) │ │ ││ │ │ d_model = 768, │ │ ││ │ │ Dropout = 0.1 │ │ ││ │ └─────────────────────────────────────────────────────────┘ │ ││ │ ×8 │ ││ └───────────────────────────────────────────────────────────────┘ ││ ││ (with padding mask support) │└──────────────────────────────┬─────────────────────────────────────┘ │ │ Aggregated Features │ (B,N,768) ▼┌─────────────────────────────────────────────────────────────────────┐│ OUTPUT HEADS ││ ││ ┌──────────────────────┴──────────────-────────┐ ││ │ │ ││ ▼ ▼ ││ ┌─────────────────┐ ┌─────────────────┐ ││ │ Stage Head │ │ Subtask Head │ ││ │ (Classifier) │ │ (Regressor) │ ││ │ │ │ │ ││ │ Linear(768→512)│ ┌────────────────┤ Concat: │ ││ │ ReLU │ │ │ - Features(768)│ ││ │ Dropout(0.1) │ │ │ - Logits(100) │ ││ │ Linear(512→100)│─────────┘ │ │ ││ │ │ │ Linear(868→512) │ ││ │ Stage Logits │ │ ReLU │ ││ │ (B,N,100) │ │ Dropout(0.1) │ ││ └─────────────────┘ │ Linear(512→1) │ ││ │ Sigmoid │ ││ │ │ ││ │ Scalar Progress │ ││ │ (B,N) │ ││ └─────────────────┘ │└─────────────────────────────────────────────────────────────────────┘ Data Flow Explained 1. Input Processing The model accepts three types of inputs for each sequence: Image Frames (B, N, 3, 224, 224): A batch of N RGB images per sequence Joint States (B, N, D_state): Robot proprioceptive information (joint angles, positions, etc.) Task Index (B,): An integer identifying which task is being performed Where B is the batch size and N is the maximum sequence length, the actual data can be shorter and then we pad it. For every prediction, our model processes a sequence of frames, deliberately structured to provide maximum temporal context: Global Anchor Frame: The first frame of the episode is included in every sequence. This is a crucial engineering choice for long-horizon tasks, as it gives the Transformer a global, unchanging reference point for the task’s initial state. Subsampled Context Frames: Several preceding frames are included to capture recent history. Current Frame: The frame for which the progress prediction is required. 2. Encoding Stage Each modality is processed through its own encoder: Visual Encoding: Images are flattened from (B, N, 3, 224, 224) to (B*N, 3, 224, 224) Passed through a frozen CLIP ViT-B/32 model to extract visual features CLIP outputs 512-dimensional features per image Features are projected to the model dimension (768) via a linear layer Reshaped back to (B, N, 768) State Encoding: Joint states are normalized using LayerNorm Projected from dimension 256 to 768 via a linear layer Output: (B, N, 768) Task Encoding: Task index is converted to a learned embedding vector The embedding is replicated across the sequence: (B,) → (B, 1, 768) This embedding is broadcast and added to all timesteps 3. Multimodal Fusion The three encoded representations are combined: input_embeddings = visual_embeddings + state_embeddings + task_embedding Additionally, a learned positional bias is added only to the first frame: input_embeddings[:, 0, :] += positional_bias This creates a unified representation (B, N, 768) that contains information from all modalities. 4. Transformer Backbone The combined embeddings are processed through an 8-layer Transformer encoder: Architecture: Standard Transformer encoder with 12 attention heads Dimensions: 768-dimensional hidden states, 3072-dimensional feedforward layers Padding Support: The model accepts an optional padding mask (B, N) where True indicates padded positions Output: Aggregated features (B, N, 768) that capture temporal and multimodal dependencies 5. Dual Output Heads The model produces two types of predictions: Stage Head (Classification): Takes the aggregated features (B, N, 768) Passes through: Linear(768→512) → ReLU → Dropout → Linear(512→100) Outputs stage logits (B, N, 100) representing 100 possible task stages: 100 is a maximum number of task stages supported, in practice the stages will be task dependent Trained with cross-entropy loss Subtask Head (Regression): Concatenates aggregated features with stage logits: [features, stage_logits] → (B, N, 868) This conditioning allows progress estimation to be stage-aware Passes through: Linear(868→512) → ReLU → Dropout → Linear(512→1) → Sigmoid Outputs scalar progress (B, N) in the range [0, 1] Trained with MSE loss Loss Computation The SARMWithLoss wrapper handles training: Masking: Only non-padded positions are included in loss calculation Stage Loss: Cross-entropy between predicted logits and ground truth stage labels Progress Loss: MSE between predicted progress and ground truth progress values Total Loss: Weighted sum of both losses (default weights: 1.0 each) total_loss = (stage_loss_weight × stage_loss) + (progress_loss_weight × progress_loss) Including the loss calculation within the model wrapper made the training code simpler and more standard. Key Design Decisions These decisions follow the original SARM paper: Why freeze CLIP?CLIP is pretrained on massive image-text datasets and provides robust visual features. Freezing it prevents overfitting on smaller robotics datasets and reduces computational cost. Why condition subtask head on stage predictions?We estimate progress within a stage, not the whole episode, so it’s stage dependent. Why add positional bias only to the first frame?The first frame often contains important context about the initial state. The positional bias helps the model distinguish the starting point from subsequent frames. Supposedly such anchoring is very effective for video models. Why use variable-length sequences with padding? We use Rewind Augmentation when we sometimes generate longer sequences that ‘mess up’ progress on purpose by replaying older frames in the reverse order. Because of that we need to handle sequences of varied length. This augmentation is critical for the model to learn how undoing progress looks like. 3. Complex data preparation The data for SARM has to be prepared in a very particular way. The core of the sampling is implemented in the custom dataloaders here. Temporal Sampling Strategy SARM doesn’t sample frames uniformly. Instead, it uses a sophisticated sampling strategy designed to provide temporal context: def prepare_indices(ep_first_frame_idx, idx, skip_count=30, default_length=8, rewind_prob=0.05): # Sample backwards in time with skip_count intervals indices = [idx - i * skip_count for i in range(default_length)] # Always include the first frame of the episode indices.append(ep_first_frame_idx) # Reverse so time flows forward indices = list(reversed(indices)) # 5% chance: add "rewound" frames for temporal augmentation if random() < rewind_prob: num_extra = random.integers(2, 5) indices += [indices[-1 - i] for i in range(1, num_extra + 1)] return indices This creates sequences with the following structure: Sequence construction (skip_count=30, ~1 second at 30 FPS):┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┐│Frame 0│ t-7s │ t-6s │ t-5s │ t-4s │ t-3s │ t-2s │ t-1s │ t ││(start)│ │ │ │ │ │ │ │(curr) │└───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘With 5% probability, add rewind frames:┌───────┬───────┬─────────────┬───────┬───────┬───────┐│... │ t │ t-1s (again)│ t-2s │ t-3s │(curr) │└───────┴───────┴─────────────┴───────┴───────┴───────┘ Why this design? Always anchor to episode start: Frame 0 provides consistent context about initial conditions Uniform temporal spacing: 1-second intervals capture motion patterns without redundancy Rewind augmentation: Teaches the model temporal reversibility and robustness Future context avoided: Model only sees past and present, not future frames Delta Timestamps Pattern The sampling strategy is complemented by a clever timestamping scheme: DELTA_TIMESTAMPS = [HIGH_NEGATIVE_TIMEDELTA] + [-7 + i for i in range(8)]# Results in: [1e6, -7, -6, -5, -4, -3, -2, -1, 0] When applied to current timestamp t: Frame 0: Gets timestamp ≈ -∞ (approximated as episode start) Frames 1-7: Get timestamps [t-7, t-6, …, t-1] Frame 8: Gets timestamp t (current) This ensures consistent temporal windows regardless of where you are in the episode.My custom dataset SARMDataset uses a dataset provided by the BEHAVIOR codebase under the hood that allows specifying delta timestamps for more efficient sampling. Variable-Length Sequence Handling Real episodes have variable lengths, and sequences can have different numbers of frames. SARM handles this with: def collate_fn(batch): # Find max sequence length in batch max_length = max(sample["sequence_length"] for sample in batch) # Pad all sequences to max_length batched_images = torch.zeros(batch_size, max_length, C, H, W) batched_padding_mask = torch.ones(batch_size, max_length, dtype=torch.bool) for i, sample in enumerate(batch): seq_len = sample["sequence_length"] batched_images[i, :seq_len] = sample["images"] batched_padding_mask[i, :seq_len] = False # False = valid, True = padding The padding mask is then passed to the Transformer to ensure padded positions don’t contribute to attention or loss: Example batch with lengths [9, 11, 13, 9]:Padded to max_length=13:┌─────────────┬─────────────┬─────────────┬─────────────┐│ Seq 1 (9) │ Seq 2 (11) │ Seq 3 (13) │ Seq 4 (9) │├─────────────┼─────────────┼─────────────┼─────────────┤│ [V][V]...[V]│ [V][V]...[V]│ [V][V]...[V]│ [V][V]...[V]││ [P][P][P][P]│ [P][P] │ │ [P][P][P][P]│└─────────────┴─────────────┴─────────────┴─────────────┘ V = Valid token P = Padding token (masked out) Inference Sampling Strategy To use SARM for VLA training, we need to run our original video dataset through SARM. But that dataset was huge to begin with! But we don’t need to evaluate every frame (with its proceeding sequence). With 5-second sampling at 30 FPS, I evaluate only 1 out of every 150 frames (5s × 30 FPS), reducing computational cost by 150×. I implemented a following dataloader (source). Why jitter? Jitter prevents the model from overfitting to fixed timestamps and produces more robust progress estimates by sampling at slightly varied intervals rather than exact multiples of 5 seconds. See INFERENCE_README for more details on the inference. Translating the progress to VLA training weights Additionally I implement the progress mapping to the weights following the SARM paper (equations 8-9):- Computes progress deltas r̂ᵢ = φ(t+Δ) - φ(t)- Uses running statistics (μ, σ) to normalize- Applies linear ramp between (μ - 2σ) and (μ + 2σ)- Optionally uses threshold κ for decisive weighting See the code in weight utils. 4. Training & Results This implementation of SARM was multi-task, however since there was so much data, I decided that it would be easier to evaluate and visualize it on a single task first. Having 200 episodes for each task, I divided the data into the following sets: “train_episodes”: 1-90, “val_episodes”: 91-105, “test_episodes”: 106-200 In general performance on the validation set wasn’t the best indicator of actual model performance when I analyzed it on the test dataset. Training for more steps was helpful. For training details see the config and the training script. The 10k-step snapshot has been trained on a single RTX5090 over several hours. The model is also compatible with training on MPS. The key bottleneck was the dataset access and video processing. Visualizations & analysis I performed detailed analysis on how well the models were predicting the progress here. Ground Truth First, it’s important how the ‘ground truth’ data looks like, here is a visualization: Based on the data annotations and the stage statistics I was able to generate our ‘Ground truth’ of progress. It was also a useful sanity check if the ground truth data looks right, e.g. having negative progress in the ground truth data would mean that there were bugs. We were only adding ’negative progress’ through the Rewind augmentation later on. Comparing models vs ground truth and each other Model checkpoint comparison vs ‘ground truth’ on a sample of episodes: The first 3 episodes were in the training data and the 2 last ones weren’t present.You can see here that the yellow (10k steps) model is better fitted to the data in the training set. Understanding the bias of the model So the model wasn’t perfect, what type of mistakes was it making? Overall, the model was leaning towards underestimating the progress. And the key problem was from predicting wrong stage number. Applicability and Limitations The caveat here that the task 8 was multimodal, the stages could be done in variable order, breaking the fundamental assumption of the fix stage order in SARM. Visualizations for a task fitting SARM assumptions would look better. The SARM Assumption: Stage-Aware modeling assumes a generally linear path through semantic checkpoints (Stage 1 $\rightarrow$ Stage 2 $\rightarrow$ Stage 3…). The Failure Case: Multimodal Progress: If a task allows for subtasks to be completed in an arbitrary order (e.g., “Tidy up the room”), the progress estimation becomes inherently multimodal, and our regression model, forced to average these possibilities, loses accuracy. Handling different sequences of stages in demonstrations Removing outliers If the majority of demonstrations are done in a consistent way, then we can remove the outlier demonstrations that create confusion. (Annotations to generate ground truth are enough to blacklist such episodes). Subtask splitting The SARM model implemented here can handle multiple tasks. Therefore, if a task can be done using different sequences of stages, we can transform it into set of related tasks with different demonstration variations. If there are multiple different ways represented in similar proportions, e.g. ‘pick up toy 1’ then ‘pick up toy 2’, and the reverse, we can change into two tasks pick_up_toys_1_2, pick_up_toys_2_1. Equal sampling We can also decide not use SARM for such tasks. SARM in Behavior challenge For the BEHAVIOR challenge specifically, we were very time constrained, and we ended up not having enough time to apply the model for the final checkpoint training, additionally, only about 30% of tasks fulfilled the fixed stage ordering for SARM. We performed quick fine tuning with weighted sampling earlier on a subset of data (not based on SARM), but it was difficult to see if it was actually helpful (eval in general was pretty challenging). Despite these challenges, SARM remains a promising approach for datasets with proper stage annotations and sequential task structure. Our analysis on the 30% of tasks with fixed stage ordering showed the model could accurately track progress. For the remaining tasks, the subtask splitting approach outlined above could make SARM applicable, potentially enabling more efficient VLA training through intelligent data selection across the full dataset.

14th Dec 2025 • 1 votes
Robotics Hackathon in Bimanual Manipulation in Munich

How a LinkedIn Post Led Me to a Munich Basement with Millions of Euros Worth of Robotics Equipment My LinkedIn feed has become a stream of robotics content over the past few months. As someone diving deep into AI robotics after years in ML/AI/RL, I’ve been deliberately connecting with people pushing the boundaries of the field. So when Nicolas Keller’s post about Munich being “the world’s best place to build robots” appeared in my feed, it immediately got my attention. A bimanual manipulation hackathon in Munich, organized in just three weeks. How cool is that? Here’s what they promised: Hands-on with dual-cobot humanoid upper-body setups, 2 Franka Emika Pandas, 2 depth cameras, 1 rgb, RTX5090 in each station Teleoperation with Meta Quest VR headsets Contributing to the MINGA research paper (with co-author potential) Collaborating in Munich’s growing robotics ecosystem I had three weeks to apply, get accepted, and arrange travel during what turned out to be Oktoberfest (the Lederhosen on the robot in the picture should have been a hint! It just made the stay extra expensive). I have recently missed the LeRobot’s worldwide hackathon and wanted to jump on the opportunity. The prospect of 30+ dual-arm robot setups, high-end GPUs, industry mentors and meeting other people passionate about robotic manipulation made it a no-brainer decision for me. The hackathon experience Most hackathons are short and they only involve software. Hardware Hackathons are much more rare, especially where hardware is provided and high end. The organizers promised a lot - and I have to say that they over-delivered, even though they operated on a very short timeline! 3 weeks! The hackathon wasn’t perfect; we hit some technical issues with the provided codebase and the robot controllers.The lab space (KI Fabrik in the Deutsches Museum) was full of amazing robots, powerful workstations, and a 3D workshop, but it also had its downsides - it was hot, humid and you could get trapped there due to the limited number of keys! The schedule was focused on building: after one day of setup and tutorials, it was essentially “09:00–open ended — Building time” for six straight days. The main communication happened on Discord. The setup was industrial-grade: 30+ Franka Emika Panda dual-arm configurations for about 40 participants. Each setup came with Meta Quest headsets running custom teleoperation software. There was a full workshop with 3D printing capabilities for custom grippers. The compute power was serious—workstations with the latest hardware that most of us don’t have access to. The initial goal of the organizers was to attract local students (mostly from TUM), but the hackathon was just too attractive. The organizers ran the selection process based on a Typeform where you had to justify your presence (CV, motivation, experience) and the final mix of people contained: PhD researchers, startup founders, industry engineers, and ambitious students. There was a significant number of people who traveled from other countries. Everyone wanted to be there. Industry engagement and realistic use cases The real differentiator was the industry backing. BMW and Siemens provided realistic challenges to be solved, explained the details, provided physical materials and sponsored prizes. Additionally, there were helpful lectures and mentoring from Nvidia, Hugging Face LeRobot and KIT (a big German university). When Sunday’s final presentations came, BMW and Siemens employes showed up to judge the results personally. This wasn’t academic theory - teams were working on problems that companies actually need solved, with the decision-makers accessible throughout and present for the final outcomes. The main organizers were TUM and Poke & Wiggle. I was very impressed with both. TUM showed great support for students and entrepreneurship. Poke&Wiggle people pulled everything together from the technical side. They were staying late and even hosted some participants coming from abroad in their homes! They were testing their own software stack while building what they claimed would become the largest public bimanual manipulation dataset. My strategy & Learning Probably my favorite thing about this hackathon was that it was extremely collaborative. Yes, people tried to win, but I was able to learn both from my team as well as from others. Team formation & collaboration I came to the event without knowing anyone and needed to form a team. It was actually a pretty common experience, many people didn’t know who to pair with. I have been in setups like this before and that experience helped. To form a good team you want the best people, but also it’s really hard to assess people very quickly and people who seem great at the start might not be able to give the best performance. E.g. they might not be fully available, you might not get along very well, etc. So my strategy was to talk to most people, see how they think and how experienced they are. I was selecting for getting along, enthusiasm and general intelligence. It was less important to me that someone was inexperienced as long as they were energetic and open minded. We weren’t the most effective or best organized, but we really enjoyed our time together, made good progress and learned a lot. Our team also shifted a bit during the 7 days (one person got sick and we adopted another one). We used a WhatsApp group to share resources, set up a GitHub repo for shared scripts and shared some notes on a Google doc. Our strategy was as follows: get familiar with the teleoperation trying out all available tasks and assess the task feasibility for the human operators train and deploy the models ASAP to test the pipeline (yes, we detected bugs and further limitations) pursue the most promising tasks, refine the dataset collection and experiment with the models for good performance Learnings We didn’t manage to win any categories. I think that my group was more focused on learning and experimentation, instead of purely competing to win. Some takeaways: If the task can’t be done by the human, the robot won’t be able to do it Training loss during model training is not a good predictor of the real life performance Robot safety mechanisms were critical to avoid breaking the robot Evaluation in real life is risky and some simulation setup would be helpful End-effector control with inverse kinematics was often causing the robots to get stuck due to joint limits; it required special care during teleoperation for the demos so that the actual policy wouldn’t block the robot Two arms are much harder than one Dataset quality matters a lot (recovery examples, non-Markovian states are confusing, noise/operators in the setup) What we tested 3 different task setups with hundred+ demonstrations each variations in model training (steps, parameters, models, action space) and dataset selection (recovery episodes ratio, bad episodes) different control modes (delta and absolute) we could only try actions in the EE space, the joint space controllers weren’t working correctly SMOLVLA and ACT models from Lerobot libraries performed experiments for generalization and resilience (e.g. messing with cameras was making robots much less effective) we also visualized attention maps for the ACT Models Here is an example of an attention map: (Kudos to physical AI Interpretability Repo - the author was there during the event and helped us a bit with the setup). Misc I got a pretty good feel for teleoperation in VR (it’s hard though!) I managed to get the arms to crash with each other and got my robots stuck countless times I spent some time setting up a simulation environment with Panda in MuJoCo and playing with Isaac Sim (approach abandoned in the end) I read several papers recommended by other participants I wasn’t able to try Pi0/Pi0.5 as the ready snapshots are for the same type of robot (Panda), but in a very different action space and we didn’t have time/resources for fine-tuning from scratch (80GB+ GPU memory required) What I wished I could do: try out Groot / Pi0.5 simulation, sim-to-real, and RL fine-tuning for the trained VLA (a simple VLA would be perfect!) Posts describing the experiences of some of my teammates: @Artur and @Andrea. We Need More of This After seven days of intense collaboration in a basement, we didn’t revolutionize the future of robotics, but we all learned a lot and everyone came back home more experienced and inspired. It was a great event! And I want to see more events like this in Europe, because the future of robotics doesn’t have to happen in SFO (or China) Europe has the ingredients for world-class robotics innovation. We have strong engineering talent and strong reasons to invest (aging population)! I live in Poland now, a place that produces some of the world’s best software engineers, but the innovation is lacking. I talked to two universities in Warsaw and they don’t really innovate or even follow the current state of the art yet for embodied intelligence. And it’s a shame, because with libraries such as LeRobot, open hardware, and open-source simulation engines, the space is now much more accessible. I was very impressed with TUM and many of the students. I would like to support the ecosystem in Poland and Europe. Munich proved it’s possible. Let me know if you would like to help! Next steps I left the event pretty drained, but also very excited! JI am still following up on the various threads I started during the hackathon. I also started to look at another exciting challenge that is focused on household tasks in the simulation. Currently I’m especially interested in the approaches combining VLAs with RL, like the ones outlined in the SimpleVLA paper and would love to participate in more hardware hackathons, ideally combining simulation and real world learning.

5th Oct 2025 • 1 votes
Creating a Robotics Experimentation Environment: My Experience and Practical Lessons

Part 1 of a series on practical robotics experimentation As part of my journey into robotics, I found myself facing a classic problem: I wanted to experiment with different learning approaches for robotic manipulation, but I needed a flexible playground where I could quickly test ideas without being locked into any single framework or workflow. The result is gym-so100-c, a simulation environment built around the Standard Open Arm SO101 that bridges multiple machine learning libraries—Stable-Baselines3, the imitation library, and Hugging Face’s LeRobot—all in one cohesive environment. The “Sim-First” Decision Even though I had access to physical robots, I chose a sim-first approach for a simple reason: I’m more of a software person who enjoys the comfort of my home office and the flexibility to keep working while traveling, rather than spending long days in a lab. This decision shaped everything about the project. I needed a simulation that was: Physically realistic enough to eventually transfer to hardware Fast enough for thousands of training episodes Flexible enough to work with different learning paradigms Simple enough that I could understand and modify every component Why Build Another Gym Environment? You might wonder: why not just use an existing simulation? I wanted something both flexible and reflecting my hardware platform well in simulation. The robotics world offers many compelling options. The Simulation Landscape I Considered: Isaac Sim was tempting—NVIDIA’s powerhouse with photorealistic rendering and advanced physics. But it requires a proper GPU setup, and I wanted to start experimenting immediately rather than waiting for hardware upgrades. ManiSkill is an exciting newer option with great task diversity and modern ML integration. I’m actually quite excited to try this next—it seems to hit the sweet spot of realism and ease of use. Gazebo/ROS represents the traditional robotics stack: mature, well-supported, with endless plugins. But the learning curve felt steep for someone coming from a pure ML background, and I wanted to focus on learning algorithms rather than robotics middleware. PyBullet similar to MuJoCo. Also popular in RL enviornments. Why I Chose MuJoCo + gym-aloha:The answer came down to immediate productivity. I could adapt gym-aloha and start experimenting within days, not weeks. It’s proven in the papers I was trying to replicate, has excellent contact modeling for manipulation, and enjoys a large ecosystem of compatible tools. The Gym Interface Standard:OpenAI Gym (now Gymnasium) defines a standard interface that every reinforcement learning environment implements: obs, info = env.reset() # Start a new episodeobs, reward, terminated, truncated, info = env.step(action) # Take an action This simple interface is incredibly powerful because it means the same environment can work with: RL libraries like Stable-Baselines3 (SAC, PPO, HER…) Imitation learning libraries like imitation Custom training loops or evaluation pipelines Any future framework that follows the standard The Evolution Plan:This environment is just the beginning. As I move toward more realistic scenarios, I’ll likely migrate to Isaac Sim or ManiSkill. But for rapid prototyping and algorithm comparison, this MuJoCo setup has been perfect. Key insight: There are many good options. If your requirements are not very specific, look for something popular and that has something similar to what you need that you can quickly adapt. This flows naturally from the question and sets up the technical details that follow. Standing on the Shoulders of ALOHA Rather than building from scratch, I adapted the gym-aloha project, which implements the dual-arm ALOHA platform used in several influential imitation learning papers. The ALOHA Foundation:ALOHA (A Low-cost Open Hardware Arm) proved that effective manipulation learning was possible with relatively simple hardware. The gym-aloha implementation provided: MuJoCo physics foundation Well-designed observation and action spaces My Adaptation:I modified gym-aloha for a single SO101 arm (5-DOF + gripper) to match my hardware target: # Simple registration exampleregister( id="gym_so100/SO100CubeToBin-v0", entry_point="gym_so100.env:SO100Env", max_episode_steps=700, nondeterministic=True, kwargs={"obs_type": "so100_pixels_agent_pos", "task": "so100_cube_to_bin"},) Once registered, creating the environment is straightforward: import gym_so100 # triggers env registrationimport gymnasium as gymenv = gym.make("gym_so100/SO100CubeToBin-v0")obs, info = env.reset() The Task: Cube-to-Bin I focused on one fundamental manipulation task: bin-a-cube. A red cube starts at a random position on the table, and the goal is to place it inside a fixed gray bin. This task is deceptively simple but covers the core challenges of manipulation: Perception: Locating the cube and understanding spatial relationships Planning: Approaching the cube from a graspable angle Control: Executing smooth, coordinated motion Manipulation: Grasping, lifting, and precise placement The MuJoCo scene includes: Robot: SO101 single arm with position-controlled actuators Workspace: Table, free-moving cube, and goal bin Sensors: Joint positions, gripper state, and camera views Sites: Tracking points for reward computation and success detection Control Paradigms: Joint vs. End-Effector Space Following gym-aloha’s design, I implemented joint-space control where actions directly specify target joint positions: Aspect Joint-space control Action Target joint positions → data.ctrl Control loop Actuators drive joints toward commanded positions Learning Policy learns in robot’s natural DOF Transfer Direct mapping to real hardware I chose joint-space over end-effector control for cleaner transfer to my target hardware. While end-effector control (where you specify gripper poses and let MuJoCo’s constraints solve for joint angles) can be more intuitive, it adds complexity that I wanted to avoid initially. What’s Inside the Environment As of August 2025, gym-so100-c includes: Simulation Environment & Tasks: MuJoCo-based SO101 simulation environment Cube-to-bin task with configurable reward shaping Training Integration Scripts: Reinforcement learning with Stable-Baselines3 (SAC) Imitation learning with the imitation library Training integration with LeRobot (ACT, Diffusion, VLAs) Control & Data Collection: Teleoperation via keyboard or gamepad Episode recording for demonstration datasets Dataset conversion to LeRobot format Early Design Lessons Physics Engine Choice: MuJoCo was the obvious choice for its speed, stability, and excellent contact modeling. It works well on CPU, it was perfect on MacBook. I am excited about IsaacSIM, but I don’t have a powerful GPU yet. I am open to trying other engines in the future. Observation Space Design: I experimented with different observation combinations: pixels_agent_pos: Camera images + joint positions agent_pos: Joint positions only (for faster training) pixels: Camera images only (for vision-based policies) The mixed approach (pixels_agent_pos) worked best, giving policies both rich visual information and precise proprioceptive feedback.This is also what ACT paper and most SOTA approaches are using. Reward Engineering: In Reinforce Learning an agent collects rewards interacting with the environment and tries to maximize them. The trick is to make such rewards that the agent does what you want from it and also that it can learn pretty well. Shaping the reward structure (designing the incentives) is called Reward Engineering and it’s suprisingly tricky to get right! For example if you reward getting close to the block too much, the agent might chose to hover over it and never grab it. If you don’t give any rewards until the task is complete and if the task is too hard, there is no feedback to learn from. I implemented both sparse rewards (success/failure only) and dense rewards with approach shaping. Dense rewards proved much more reliable for learning, though they required more careful tuning. I also implememented HER (hindsight experience replay) that automates the reward shaping by trying to teach the robot behaviors from previous trajectories, but the results were mixed in my setup. The Integration Challenge The real value of this environment isn’t just the simulation — it’s the integration layer that lets me seamlessly move between different learning approaches. In the next post, I’ll dive into what I learned from training experiments with SAC, behavior cloning, and modern imitation learning methods. But the foundation was crucial: having a single environment that could work with multiple learning paradigms, generate consistent datasets, and provide reliable evaluation metrics. Sometimes the unglamorous infrastructure work is what makes everything else possible. Next up: Training experiments and what I learned about the practical differences between reinforcement learning and imitation learning approaches. What’s your experience with simulation environments for robotics? Have you found certain design decisions that made experimentation much easier or harder? I’d love to hear about it.

13th Aug 2025 • 1 votes
Generating Hundreds of Consistent Illustrations with Gemini Image Generation

A deep dive into building an automated illustration pipeline for storytelling applications Introduction AI image generation has revolutionized creative workflows, but there’s a significant difference between generating a single stunning image and producing hundreds of consistent illustrations for a complete project. When building storylearner.app, we faced the challenge of generating book illustrations that maintained visual consistency while telling compelling stories through imagery. We’ve used powerful Gemini multimodal models, mostly because they are fast and because the experimental ones are available for free. This article explores the technical and creative challenges of large-scale AI illustration generation, showcasing techniques for achieving visual consistency and building robust pipelines that can handle the complexity of full book illustration projects. Below are images created for a chapter of a book adapted for the storylearner platform: The article has a companion colab notebook, so you can play with the examples yourself. The Consistency Challenge Understanding Visual Consistency in AI AI image generation models operate somewhat like a company of talented artists, each with amnesia. Every generation is essentially a fresh start unless you provide explicit context. This creates unique challenges when you need to maintain character consistency, style coherence, and narrative flow across hundreds of images. Consider this simple experiment: generating three images of “the same pig with wings and a top hat flying over a futuristic city” in different weather conditions. Even with identical prompts and seeds, subtle inconsistencies emerge—eye colors change, proportions shift, and the overall character can feel different. The Impact of Seeds and Prompts Seeds act like selecting a specific artist from your AI company. Using the same seed with identical prompts yields consistent results, but even small prompt variations can dramatically alter the output. We discovered that: Same model + same prompt + same seed = identical results Same model + same prompt + different seed = completely different character Same model + slightly altered prompt + same seed = often produces a different character entirely This sensitivity means that scaling up requires careful orchestration of all these variables. Building Consistency Through Reference Images The Reference Image Approach The most reliable method we found for maintaining character consistency involves using reference images. Here’s how it works: Generate an initial character/scene using carefully crafted prompts Upload this image as a reference for subsequent generations Include explicit instructions like “Use the supplied image as a reference for how the pig should look like” This approach significantly improves consistency, though it can also cause new issues in some very specific cases. With the following reference image: You can get this different, but consistent one! Here is an example of triggering a specific case: This specific case can happen when a prompt is pretty similar to the one that generated the initial image and the seed is identical.So, when using the reference image and similar prompt, I would actually recommend to change the seed or not set it. See the reference colab for details. Practical Implementation # Upload reference imagefiles = [client.files.upload(file="reference_character.png")]# Create parts with reference and promptparts = [ types.Part.from_uri( file_uri=files[0].uri, mime_type=files[0].mime_type, ), types.Part.from_text( text=prompt + "\nUse the supplied image as a reference for character appearance" ),]# Generate with referenceresponse = client.models.generate_content( model=IMAGE_MODEL, contents=parts, config=types.GenerateContentConfig( response_modalities=['Text', 'Image'], # No seed set. )) The Storylearner.app Illustration Pipeline High-Level Architecture Our production pipeline consists of three main stages: Idea Generation: Story text + guidelines → 3 illustration concepts per scene Idea Selection: Multiple concepts → best ideas chosen for the complete set Image Generation: Selected ideas + style guidelines + reference images → final illustrations Stage 1: Brainstorming Illustration Ideas Rather than feeding story text directly to image generation (which often produces poor results), we separate conceptualization from execution: class IdeaGenerator: def generate_illustration_ideas(self, text: str, context: str): prompt = """ You are a visual scene designer. Based on the story below, describe 3 different highly detailed and imaginative illustration ideas. Do not include any people or humanoid figures. Focus on setting, atmosphere, lighting, symbolic objects, and environmental storytelling. Story: {text} Context: {context} """ # Returns 3 detailed scene descriptions per text excerpt This approach generates rich, detailed scene descriptions that serve as blueprints for image generation. Stage 2: Intelligent Selection To avoid repetitive illustrations (like “a ship, a ship, a ship” in a sea voyage story), we use an AI selector to choose the best combination of ideas: class IllustrationSelector: def select_illustrations(self, chapter): prompt = """ Choose the best idea for each illustration considering that: - The set should be diverse - Illustrations shouldn't contain people - Prefer illustrations matching the provided titles """ # Returns optimal selection indices Stage 3: Consistent Generation The final generation stage uses: Style guidelines (detailed visual specifications) Reference images for style consistency Persistent chat sessions for maintaining context Retry mechanisms for handling API limitations Visual Guidelines and Style Consistency Crafting Effective Style Guidelines We developed comprehensive style guidelines that go beyond simple style names: Style: watercolorTechnique: Combine soft watercolor washes with fine ink line work for contrast and detail.Brushwork: Embrace visible brush strokes, blooming, and natural texture.Ink Lines: Use varied line weights for depth; apply cross-hatching or stippling for texture.Color Palette: Limit to a few harmonious hues with gentle gradations.Forms: Use simplified, geometric shapes; focus on essence over detail.White Space: Treat negative space as part of the composition.Texture: Highlight watercolor paper's natural texture and color variation.Atmosphere: Create light, airy scenes with openness and subtle contrast.Aesthetic: Preserve a hand-drawn look—embrace imperfections and human touch. Chat-Based Generation for Context Continuity Using persistent chat sessions helps maintain consistency within illustration sets: def generate_set_of_illustrations(ideas_with_file_paths, pass_image=True): chat = client.chats.create( model=IMAGE_MODEL, config=types.GenerateContentConfig(response_modalities=["Text", "Image"]), ) # Initialize with style guidelines and reference image initial_prompt = f""" You are a creative artist helping on an illustration project. Create {len(ideas_with_file_paths)} beautiful illustrations. VISUAL GUIDELINES: {VISUAL_GUIDELINES} """ # Generate each illustration within the same chat context for idea in ideas_with_file_paths: response = chat.send_message(format_illustration_prompt(idea)) # Process and save generated image Avoiding Common Pitfalls Critical Design Decisions Through extensive experimentation, we identified several key strategies: Avoid Human Close-ups: Character face consistency is extremely challenging. Focus on environmental storytelling instead. No Violence or Gore: Keep illustrations family-friendly and avoid content that might trigger safety filters. Diversify Scene Types: The selection stage prevents repetitive imagery across the complete set. Decouple Ideation from Generation: Separating concept creation from image generation improves both quality and debuggability. Real-World Example: Illustrating The Three Musketeers Let’s walk through illustrating a chapter from The Three Musketeers: Context and Settings First, we establish the story context: Setting: France, primarily Meung and Paris, early 17th centuryHistorical Context: Political tensions between French monarchy and Cardinal RichelieuMain Characters: D'Artagnan, Athos, Porthos, Aramis, Cardinal Richelieu, Milady de Winter Generated Ideas For the chapter opening, our system generated these concepts: “The Jolly Miller Inn Chaos”: Exterior scene with a yellow pony, scattered debris, and dramatic lighting hinting at recent altercation “Broken Sword”: Close-up of shattered steel on cobblestones, symbolizing lost honor and broken dreams “Inn Kitchen Aftermath”: Dimly lit interior with earthenware, bandages, and flickering candlelight Selection and Generation The selector chose the most diverse and narratively appropriate ideas, which were then generated using our reference image and style guidelines, producing illustrations that maintain visual consistency while telling the story effectively. Key Insights and Best Practices Consistency vs. Perfection: Perfect consistency isn’t always necessary—visual coherence in style and mood often matters more than exact character matching. The Artist Analogy: Think of AI models as artists with amnesia. You need to provide context, references, and clear instructions for each interaction. Pipeline Modularization: Breaking the process into idea generation, selection, and execution improves quality and maintainability. Style Guidelines Matter: Detailed, specific style descriptions work better than simple style names. Reference Images Are Crucial: Upload and reference style examples for best consistency results. Long Sessions are Fragile: It often works until a point, and at some point it fails poorly, e.g. inserting objects from a previous illustration into the following ones. Conclusion There is still a huge gap between a carefully handcrafted demo on an AI company blog and practical usage of the technology at scale. Things don’t work out well straight out of the box, but you can make these amazing tools work for you with help of systematic thinking about consistency, quality control, and robust engineering practices. While challenges remain, I hope you’ll enjoy the techniques we’ve developed at storylearner.app to power your own projects!

20th Jul 2025 • 1 votes
Escaping LLM piping mess with nifty engineering

In this post I’ll walk through how I upgraded a set of tangled Python notebooks—responsible for thousands of LLM calls—into a robust content-adaptation studio powered by: an async FastAPI pipeline, a disk-first Next.js frontend, and a small suite of custom CLI tools. Re-engineering the stack was essential for my own sanity: the notebooks were fragile, slow to iterate on, and far too labor-intensive to babysit. I was also facing content quality challenges that were pretty much impossible to address in the old code base, that re-engineering unlocked. My hope is that the story also nudges you to build (or level-up) your own tooling instead of settling for one-off notebooks. We’ll cover: Engineering constraints – huge text volumes, strict meaning preservation, multiple target languages. The original notebook setup – what worked and where it hurt. Pain points – why small hacks no longer cut it. The new architecture – key design choices, novel elements (with screenshots), and how they solve the earlier pain. Outcomes & takeaways – higher quality, less toil, faster experiments, and patterns you can reuse in your own LLM workflows. Shape of the problem Shape of the problem: large quantities of text that need to be processed in a very specific way: retain meaning of the original (no text disappearing or altered significantly) consistent between parts translated & simplified resulting content needs to consistently have good quality automatic quality assessment and quality repair (revisions) A similar challenge would be relevant in translating legal documents, healthcare documents, etc. Story Learner Book Adaptation needs In my project StoryLearner I offer adapted books for language learning at a specific level. For example, “Las Aventuras de Sherlock Holmes, in A2, Spanish”. We use LLMs for both language/level adaptation as well as for illustrations.It’s a lot of LLM calls (easily thousands for a single book), because books are long and there are many elements for a single adaptation. A book has chapters, chapters have parts for easier reading. Each book/chapter/page has an custom illustration. Additionally, there are titles and descriptions to be adapted and transcribed. Books are long and we want the adapted text to retain the meaning, while making the language simple (aligned with the target level), natural sounding and correct. Trouble with a flaky, slow pipeline and hard to assess output The pipeline was was quite a feat! It was a lot of LLM calls, built mostly in colab/jupyter notebooks. RAW BOOK | v[book_stripping] | v[chapter_extraction] | v[chapter_simplification] (English) | v[chapter_partification] (English) | \ | \ | ---> [illustration_generation] | v[adapt] ──▶ [Lang 1] │ [Lang 2] │ [Lang 3] │ [Lang 4] │ [Lang 5] │ [Lang 6] | Illustration generation was on its own a pretty interesting pipeline (more about it in a separate post!). Here is one of the adaptation notebooks: As you can see, it has its own table of contents on the side. It’s easily thousands of lines of code and prompts. And the hundreds of outputs (text and images) could make it very, very, long. To the point that it would have rendering issues. On top of it there was: Separate notebook for book_narration Another notebook for upload to storylearner (via API). The “pipeline” worked. It serialized partial outputs in a way that partial redos/continuations were possible, it offered decent visualization. It was adjustable (just add/tweak a notebook cell!). However it was fragile and assessing quality/redoing content was painful and slow. And it was very frustrating to me, especially since the quality was important to my partners (language schools). Main pain points LLM reliability issues (no resources, surprise safety controls kicking in, running out of quota or LLMs not following instructions) broke downstream steps. The adaptation process was slow, it wasn’t taking advantage of paralellization well The pipeline was already so brittle enough that meaningful experiments were nearly impossible Colab/notebooks encouraged slapping things together instead of proper engineering with encapsulation and tests Python notebooks having rendering bugs because they were so long and had so many outputs (large text/many images) Low confidence in language level, name/format consistency, and preserved meaning without having a strict review/repair process and having some examples of problems with quality. Reviewing 60+ chapters across six languages was slow and manual - was infeasible for me. A copy of an adaptation notebook per book (for visualization/auditability) was duplicating the code and making it harder to maintain New Content Adaptation Tools I haven’t built everything at once. I started with a frontend using the existing disk format of book adaptations, then as it was easier to see what was going on, I progressively built more and more backend migrating specific functionalities. Fast API gives a nice UI out of the bat to call APIs, which was nice for trying things out. But the workflows were simply to long to drive them by hand, so that is how CLI tools came to be. CLIs/Frontend were in big part written by copilot coding agent. I also extensively discussed the component prompts with LLMs 😀. Backend – bookadaptation (FastAPI) all functionality behind endpoints, all async / internally parallel where safe (28 separate endpoints) All IO and LLM calls done async Pipeline stages are classes; 11 adapter subclasses (Gemini Flash, Gemini Pro, GPT-4o, etc.). skip and use_cached flags run a no-op or reuse artefacts while the file tree stays unchanged. STAGE_DEPENDENCIES mapping declares primary & secondary inputs and outputs for every stage. Hierarchical on-disk structure; files get a _{revision_number} suffix for multi-round outputs. Heavy use of controlled generation (using schemas) SQL instrumentation: All prompts, schemas, settings, outputs, latency, and errors logged to SQLite. Frontend – ContentTools (Next.js Server Components) Specialised views: Book language adaptations Illustrate all artefacts of the adaptation pipeline (inputs, outpus) Easy debugging of what happened during the QA Easy comparisons between experimental implementations “Final for publish” view. Illustrations: All book illustrations as grids (chapters, chapter parts) Illustration deep dives - ideas and the best ideas Reads JSON & WebP directly from disk—no extra HTTP hop. CLI tools (all async friendly python) adaptation CLI Adapts and revises every chapter until it’s good enough Drives the pipeline stages implemented in the service (many endpoints right) Gracefully retries LLM driven decisions: Uses output from the overall review to finish the chapter or go for more rounds or partially skip stages narration CLI illustration CLI publishing CLI Everything runs locally, but could as well run on a server. Yes, I ended up building a lightweight custom pipeline orchestration… 💀 Flow of a book adaptation with automatic QA (multiple revisions) RAW BOOK | v[book_stripping] | v[chapter_extraction] | v[chapter_simplification] (English) | v[chapter_partification] (English) | \ | \ | ---> [illustration_generation] | v[adapt] ──▶ [Lang 1] │ [Lang 2] │ [Lang 3] │ [Lang 4] │ [Lang 5] │ [Lang 6] | v[review_chapter] ←──────────────┐ | │ v │[revise_chapter] │ | │ v │[review_consistency] │ | │ v │[revise_consistency] │ | │ v │[review_meaning_cohesion] │ | │ v │[revise_meaning_cohesion] │ | │ v │[review_titles] │ | │ v │[revise_titles] │ | │ v │[review_chapter_title] │ | │ v │[revise_chapter_title] │ | │ v │[review_overall] ──────────────┘ | v [promote_content] | | +--> [book_narration] (from adapted text) | +--> [upload / publish] QA rounds are controlled by the output of the review_overall stage. Examples of frontend enabling fast QA Example of problematic images that can be ’easily spotted’ by a trained eye. Chapter level issues overview for an adaptation workflow: Part level debugging/review of what was suggested/applied in the QA pipeline: Review and Revision—kept deliberately apart One key design choice was to decouple “reviewer” from “reviser”. The reviewer node reads the necessary context and produces a structured list of issues,while the reviser node sees only the affected slice plus those suggestions. Why keep them separate? Audit clarity The reviewer’s JSON lives as its own artefact, so you can diff, grep, or hand-editthe feedback without touching the text itself. It’s also easier to audit automatic revisions and spot ‘additional helpfulness’. Smaller prompts, cheaper calls A reviser that operates on just the target part + suggestions uses far fewer tokensthan one that re-ingests the whole chapter. Less collateral damage Narrow context means the reviser can’t “helpfully” rewrite good paragraphs in other sections or even just completely forget them. True parallelism Parts are context-isolated, so multiple revisions can run concurrently—no giant chapter-wide lock. Targeted rollbacks If a revision introduces a new issue, it’s easy to rollback. What the flow looks like review_meaning_cohesion scans consistency_revised_stories and writes meaning_cohesion_review_1.json: { "issues": [ {{ "part_number": 1, "suggestion": "Change sentence '...sentence...' to '...corrected sentence...' to ensure consistency with previous parts.", "reason": "Inconsistent character name across parts.", "severity": "high" }}, ... ], } During the revise_meaning_cohesion stage, revisions to specific parts are applied concurrently, e.g. reviser for part 8 only sees the text of part 8 and the suggestions for part 8. Other novel elements Stable DAG via no-op nodes – skipping or caching never changes filenames or dependencies, so UI and controller logic stay simple. Declarative STAGE_DEPENDENCIES – each endpoint validates its own inputs and fails fast if artefacts are missing. Pluggable adapter subclasses – swapping models or prompt strategies is a config change, not a refactor. Direct-disk reading Server Side React Components – Suprisingly trivial frontend code. SQLite error forensics – a single query surfaces “prohibited-content” or other LLM failures. Hot-reload mid-run – tweak prompts or error handling while a 60-chapter fan-out is running; retries pick up the change without restart. WebP illustration storage – generated art compresses very well; files are roughly 10× smaller than raw outputs. LLM-driven controller decisions – the CLI uses the review_overall output to decide whether to launch another revision round and which stages to skip. Personal wins The biggest win is defending my personal sanity. I no longer have to babysit a set of fragile notebook based pipelines based on fallible and untrustworthy LLMs. Higher confidence in quality – every chapter passes level, consistency, meaning, and overall reviews—automatic multi-round fixes if needed. Far less toil – no more babysitting fragile notebooks; the pipeline self-checks and fails early. Fast, parallel experimentation – new adapters or prompts run side-by-side with hot-reload; iteration is “super fast and fun.” Cost flexibility – total spend is higher (as there are more LLM calls), but the modular design lets me fall back to cheaper or local models whenever I choose. And the cool thing is that building this tooling was heavily accelerated by a coding assistant/agent, so it was significantly faster and more fun than I would have expected from the scope of the reengineering.

25th Jun 2025 • 1 votes

More in technology

No title
an hour ago • 1 votes
The classic console corner's CRT changeover

In the corner of the rear Floodgap lab sits a pile of classic game consoles. It used to look like this: Sega Dreamcast all the consoles here only came with NTSC RF output and date from the pre-flat panel TV era. That includes multiple Atari consoles (including the inevitable VCS, here a Darth Vader 2600), several Pong machines — including two Commodore units — with various chipsets, an Intellivision (as the rebadged Tandyvision One, my first) and a Bally Astrocade with lots of upgrades. It seems wrong to use them with a flat panel, and CRTs lag less. Plus, games with a light gun (here the Dreamcast and one of the Pong consoles) often rely on the CRT's rapidly scanning beam to know where they're pointed. So what do you do when the CRT TV goes bad? I should note that this isn't all the old school gaming fun in the house. In the commons next to the pinball machines are an Xbox 360 Slim and a PlayStation 2, and in the home theatre connected to the 3D projector is a PlayStation 3 since it has some stereoscopic titles. These might appear in future articles. But most of the rest are here. I bought this Panasonic Omnivision PV-M2035 from a friend at church in 1999 for $100 [about $200 in 2026 dollars]. He had no use for it, and the top of the plastic shell had been heat-warped by sitting in his car too long, but it worked, still had the remote, and was a suitably cheap TV for my unsuitably cheap studio apartment. I used it for local news and Friends with a set of rabbit ears, VHS movies, and speakers for playing music by connecting a CD player to the single rear input. When I moved to a less cheap 1-bedroom, it came along, and its flat top was flat enough to become a shelf for a DVD player. I got the Dreamcast from Fry's in 2001 after Sega discontinued it and managed to share the composite input between them. That apartment was my crashpad for about a decade before moving to the current orbiting HQ, whereupon I bought a passive-3D flat panel TV and moved the Omnivision to its current location in the back of the house. It shared the RF input between the Inty, and later the Atari 2600, and later still the Astrocade and various Pongs. At any one time there were at least four consoles always connected to it via switches and switchboxes, and I wired up an accessory port for more. plastic was broken and on these TVs that's pretty much the load-bearing part. When it arrived at the mailbox and I unpacked it, I could see the lower half had sandwiched right through the VCR slot, with visible PCB fragments and broken buttons; aside from the tube itself (ironically), the thing was a total loss. The seller nevertheless made good on the refund, to their credit, and I got to schlep it to the recycler. Overall, however, it had occurred to me that there were very few TVs sufficiently contemporary with the M2035 out there, which might be a hint about their general longevity. So, if I was going to be forced to buy a different Panasonic, then it might as well be a more recent one, and it should be one of the "triple play" units (i.e., TV, VCR, DVD) so that I could at least get rid of the external DVD player. Mission: Impossible '88 and '89 DVD sets, where the "in stereo" animation was even burned into the video stream.) not recording and thus impossible to watch many DVDs, for which the Sima CopyMaster was the cheapest solution: it simply blots out that portion of the vertical blank along with the pulses, which also has the side effect of sometimes stripping closed captioning (in the vertical blank as well), though DVDs with proper subtitles are of course unaffected. Later Sima devices could regenerate portions of the vertical blank for better quality, and Macrovision actually sued them over their products in 2005, but later settled. The mixer on the right was purchased literal decades ago at Radio Shack (more specifically a "Video Enhancer Stereo Audio Mixer") that I think we used for a Halloween display exactly once and then forgot about. Here it was used first as a cutoff switch, and second as a way to match the audio volume from the DVD player with the audio volume from the Dreamcast, which was also directly connected to the second rear Y-cable. This TV is mono, so the stereo channels from the audio mixer and the DC get merged using their own Y-connectors (also Radio Shack) before going into the Y-cable to the single line audio input. The video function isn't used here at all; it was just a audio mixer on the shelf I wasn't otherwise using. The DVD player is under the mixer and the CopyMaster, a cheapie Sony special that will only eject discs if it's in the mood or summarily threatened with violence. You already met this system when we adjusted the laser pickup and refurbished its rechargeable battery. you met the Tandyvision One (otherwise identical to the Mattel Intellivision Master Component, and manufactured by them as an OEM) when we installed a composite video modification and a front power-cutoff reset. I later upgraded it with an original Mattel Intellivoice speech synthesizer (Tandy never rebadged these) and a CuttleCart. But you haven't met the Bally on the bottom, officially introduced in 1978 as a game console and simple home computer, sold under various names such as the Bally Professional Arcade seen on early units, later the Bally Computer System badging here, and now collectively referred to under its final incarnation as the Astrocade. These machines were based around a 1.789MHz Z80 (half NTSC colourburst) combined with the same graphics hardware Dave Nutting Associates used for Midway's arcade games Gorf and Wizard of Wor, among others. Unfortunately, much of its theoretical graphics power went unrealized because it only has half the video memory of the arcade units (i.e., 4K) — and that's all the memory it has, so it has to interleave bits in the video memory to store BASIC programs, meaning only game ROMs can take full advantage. Still, that was enough to be solid competition for the likes of the Atari VCS and Fairchild Channel F, and it holds its own well against the slightly later Intellivision. does have is a doozy: the cooling vents are on the underside. These machines are very prone to overheating and can be easily damaged by it, which is why I use two foam struts to keep it off the carpet. The yellow label is for Astrovision, a separate enterprise that had been attempting to develop their own console. The (then) Bally Professional Arcade was selling poorly, though part of this was due to a tardy launch and Bally's weak retail presence, and Bally decided to sell off the consumer products division in 1979. Astrovision, unable to get their unit to market quickly, bought it in 1981 along with a limited license to the Bally name and reintroduced it at Winter CES 1982. Astrovision units are otherwise the same except for the badging and are the most common Astrocades today, though the company became another victim of the 1983 video game crash and went bankrupt shortly afterwards. Simultaneously, an Astrocade derivative merged with Bally's unfinished ZGRASS-100 expansion chassis was reworked into the Datamax UV-1 graphics generator, sold in small numbers until around 1982. the wall warts and power strips, and do a little spot vacuuming with the Roomba. out in spring. Gremlin's Blockade; and a simple calculator and screen paint toy ("Scribbling"). The display is a bit noisier than the Inty/Tandyvision, probably because of the difference in shielding, but still quite good. Videostak Video Game Center, which allegedly could accomodate a VCS, Intellivision or ColecoVision. The front decal is somewhat worn and the woodgrain veneer doesn't match the Vader VCS nearly as well, but it's still a fun-looking setup. Intellivision System Changer which has Atari 2600 hardware in an expansion box for the Intellivision II (useable on the original Inty with modification). It might be fun to explore the reputed irregularities between what is believed to be a VTI clone TIA in the System Changer and the slightly earlier Coleco Expansion Module 1 (and the related Coleco Gemini), and see how they differ in practice. Now for the Pong machines. These attach to the "accessory port" on the input switcher. The current Pong menagerie are mostly MOS 7600-based, MOS' own Pong-on-a-chip: two from Commodore themselves but PAL only using the MOS 7601 (the TV Game 2000K and TV Game 3000H), plus two MOS 7600 (NTSC) systems, a Coleco Telstar Gemini, not to be confused with the Coleco Gemini or Coleco Telstar, and an Allied Leisure Name of the Game II, possibly the earliest use of the chip in NTSC regions. We'll play the Name of the Game II and Telstar Gemini below. These will be consoles for another day, but I also have a boxed Atari Video Pinball, an "honorary" Pong machine though it plays several other games, and a boxed Atari Ultra Pong Doubles, which we had before we got the Tandyvision, but I don't ever recall it working fully and it later failed to power up and got thrown away, so this is a replacement. My least favourite of the Pongs here (I really only picked it up because it was cheap) is a 1977 Magnavox Odyssey 3000. The 3000 is basically an upmarket Odyssey 2000 with proper handheld controllers, but otherwise the same me-too AY-3-8500 Pong-on-a-chip generating the same black-and-white display. Allied Leisure Name of the Game II is a two-player Pong based on the MOS 7600-001. This chip notionally contains three field games (a tennis game, a "goal" game usually billed as either soccer or hockey, and a racquetball game) and a skeet shooter, but the racquetball game can be put into a single player mode by setting it to "four" players and the NotG2's switch triggers this mode in place of the skeet shooter. It was noisy on the other TV and it's noisy here, possibly because it has its own internal RF switchbox, but it plays fine. Coleco Telstar Gemini, an MOS 7600-004 system. This has two "pinball" variants (with flippers and moveable Pong paddles, so it's still a Pong of sorts) and two shooting gallery variants involving shooting a deformed bear sprite. The light gun connector is the same as the Coleco Telstar, so I borrowed the gun from that. sing along with The Offspring. But the output looks crisp through the rear jacks, the sound is proper stereo, and we now have front inputs I can use for something else without rigging a whole bunch of Y-adapters again. Plus, if the Telstar Gemini's gun works, it's all but guaranteed the Dreamcast's does. am likely to play some Video Pinball, and in its box that's easy to move, so that can go on top of the 2600 and the NotG and Telstar Gemini can sit next to it. The old TV is out in the garage and as I have time I'll extract its circuit boards and go over them more thoroughly, since I had a lot of good times with that television and it would be nice to fix. If I do, I'll write it up here, since it's an actual old VCR. Meanwhile, I have some possible projects in mind for the Tandyvision and Astrocade, and maybe some mods to go in the VCS, and you can read about those in future articles too. In the end, with the new TV all set up, the 1980s can live again in my rear office. Or, as my wife likes to point out, they never actually died there either.

6 hours ago • 1 votes
Nazi Literature in the Americas

Learn by fire.

yesterday • 1 votes
iPhone Duo early review

By a mile, the iPhone Duo has garnered more questions about what I think about it than any other phone I’ve ever had. It’s clearly a phone that has people intrigued, so I thought I’d jot down some loose, unorganized thoughts about what I think about it after about ten days. If I could sum all my thoughts up into one word, it’d simply be “fun”. I think for the vast majority of people, myself included, the iPhone 18 Pro is a more practical phone that through scientific analysis you’d likely even find a better phone. Even if they were priced the same, its package is more traditionally comfortable and ergonomic, with a better quality main camera, a helpful telephoto camera, a screen that’s more practical to use more of the time, a better biometric system (Face ID versus Touch ID) and a more established software experience. But damn if the iPhone Duo isn’t fun. Phones have been downright boring for so long. Incredible technology, lovely apps, but the hardware has been a bit slow moving since the iPhone X. Maybe that’s why I jumped onto the iPhone Air so readily. Even that slight departure from “black slab of glass” to “a dramatically thinner black slab of glass” was exciting versus what we’ve grown accustomed to. So I pick up the Duo, and it’s kinda just exciting to hold a phone for the first time in ages. Maybe that’s a honeymoon period and after a few months I’ll be over it. Maybe everyone who tries a folding phone for the first time experiences this. And to be clear, it’s not just all raw novelty. The fun aspect is fueled by having an absolutely incredible inner screen that fundamentally transforms what a phone is and can be. In addition, support the Apple Pencil has turned out to be phenomenally handy for me to be able to jot down quick thoughts and notes. For downsides, Touch ID is objectively worse than Face ID, but honestly, I don’t mind it as much as I expected I would. The smaller camera sensor than the Pro series phones is still decidedly great (rumors were it was a 17e size which was not correct, it’s the size of the normal 17’s). Software support gets better by the day, though iOS on the Duo is still decidedly a bit buggy at times. Other random thoughts Touch ID is objectively worse than Face ID, but honestly, I don’t mind it as much as I expected I would, previewing notifications is where I miss it the most After getting used to having a single speaker in the iPhone Air for a year, having stereo (not to mention great sounding) speakers is amazing The FaceTime camera on the inside is indeed not great for selfies/photography but honestly perfectly acceptable for FaceTime, and I’d definitely prefer this solution over a cutout on the inside so I’m happy! It definitely has a heavy feel to it, but it’s nothing honestly that bothersome A lot of the reviews said something to the effect of “the crease is practically invisible” and while I don’t really mind it or anything I definitely would disagree with that statement, you can see it a fair bit even with light content The hinge is a bit harder to open than I expected, I’ve found the secret is don’t pry from the middle of the side, instead put a thumb near the top and bottom (also helps prevent pressing Camera Control instead which I was doing all the time). I imagine this is necessary to have it be able to stop at arbitrary angles once open (which I do like) and hopefully it loosens up a bit with more use, but playing with Android foldables at Best Buy I did find their hinge easier to open I am really split on the inner, nano texture screen. It definitely helps reflections, has a neat look to it, and is super nice to draw on with the pencil, but it’s significantly less vibrant than the outer display which to my eyes looks a fair bit nicer. I think they made the right decision ultimately but it’s definitely not a zero-compromise solution. I was considering nano texture on my next MacBook but after this I think I’ll stick with glossy. My glass half full take with the Duo for now though is that we get two really cool screens to play with The outer screen is awesome for taking photos, unlike taller iPhones, your viewfinder fills the screen completely so it’s the largest feeling viewfinder I’ve used on a phone I miss the action button, nice little launcher for ChatGPT/Claude depending on which month it is Battery life is downright phenomenal versus my iPhone Air and 15 Pro (two devices admittedly not known for having great battery life) So, I don’t think the Duo is for most people who either don’t care much about phones, or care a lot about having the perfect phone, but for a decent amount of people in the middle I think the Duo represents a fundamentally different experience, that’s a ton of fun, and I’m excited to be excited about a phone again. (But, Apple, please figure out a way to add a telephoto lens.)

2 days ago • 1 votes
Reverse engineering a vintage diode-transistor logic chip

Going through a collection of old parts, CuriousMarc encountered some ICs that he couldn't identify. He opened up one of these ICs, and I studied it under the microscope. After some reverse engineering, I determined that it was a logic chip that implemented four NAND gates using old-fashioned diode-transistor logic (DTL).1 The chip turned out to be the ST680A, a member of the Signetics 600 series of chips from 1965. In this article, I discuss the circuitry in this chip and how diode-transistor logic works. The die of the ST680A under the microscope. Integrated circuits can be packaged in many ways. One of the most popular is the plastic DIP (Dual In-line Package), a black rectangle of epoxy with two rows of metal pins. This type of package was invented by Signetics: "Introduced in late 1965, the 600 series was the first integrated circuit family to be offered in a solid, plastic, dual in-line package (DIP)." Earlier integrated circuits were packaged in round metal cans or in small flat-packs. In 1965, engineers at Fairchild invented the DIP, which had two rows of pins on 0.1" spacing. Unlike the surface-mounted flat-pack, the DIP had pins that were inserted into holes, making manual or automated assembly quick and easy. Because the pins of a DIP were on a regular grid, rather than the circular pattern of a metal can, circuit board design and manufacturing were also easier (details). The first DIP chips had ceramic packages. The plastic DIP, introduced by Signetics, was much cheaper and became very popular. An advertisement for the Signetics 600 series. From Electronics, March 21, 1966. The plastic DIP is less popular with me, however, because it is harder to open. With a ceramic package, I can simply tap it with a chisel and pop it open, but that doesn't work with epoxy packages. An epoxy package can be dissolved with nitric or sulfuric acid, but I try to avoid dangerous acids. Instead, CuriousMarc used Antoine's hot air decapping method. Unfortunately, the hot air technique doesn't always work. In this case, tiny bits of epoxy were stuck to the die, obscuring the circuitry. I used a few drops of boiling sulfuric acid to clean the die. (I'm okay with sulfuric acid in tiny quantities.) The die on its metal frame. The photo above shows the silicon die on its metal frame, the lead frame. The golden blobs are where the bond wires were attached to the die. You can see the doped silicon regions that form diodes and bipolar NPN transistors, as well as 16 resistors in the center, forming serpentine paths. Most chips have a passivation layer—a thin layer of silicon dioxide—over the chip. Inconveniently, this old chip didn't have a passivation layer, so the acid also stripped off the metal layer. (A few remnants are visible in the upper left.) Without the metal layer, I had to guess at how the components were connected to form logic gates. The die has very faint color differences where the silicon was protected by the metal, so that helped. Eventually, I came up with the diagram below, showing how the metal layer was probably configured. This wiring reveals that the chip implements four DTL NAND gates, which I'll describe in more detail below. One puzzle was that the chip has two unused diodes, indicated with question marks below. The metal layer for a quad NAND chip. I desaturated the image to make the labels clearer. Transistors, diodes, and resistors In this section, I'll explain how the patterns in the image correspond to components of the circuit. The silicon die is doped with various impurities to form regions with different electrical characteristics. These regions appear red or green under the microscope due to thin-film effects. As a result, the chip's transistors, diodes, and resistors are visible. The chip is made from bipolar NPN transistors, which have a completely different construction from the MOS transistors in modern ICs. In an NPN transistor, the current from the collector to the emitter is controlled by the current through the base. The collector is a large region of N-type silicon, silicon that is doped with atoms such as phosphorus or arsenic. Since these elements have one more valence electron than silicon, they give the silicon more negative charge carriers, so it is called N for negative. The N-type silicon happens to appear reddish. On top of the collector, the base is a thin region of P-type silicon, which appears green. This silicon has been doped with atoms such as boron or gallium, which have one fewer valence electron than silicon. The missing electrons form "holes", which act as positive charge carriers. Finally, the emitter is N-type silicon, on top of the base layer. These layers work together through semiconductor magic, amplifying the base current. Two NPN transistors on the chip. The second transistor is a larger output transistor. The chip's output transistors are slightly larger so they can sink more current. In the transistor on the right above, note that the collector contact wraps around three sides of the transistor. The emitter is also larger, with an L-shaped contact. According to the datasheet, each output transistor can sink 2.5 mA of current. The chip uses many diodes since it is diode-transistor logic. The structure of a diode is similar to a transistor, but without the emitter. In a diode, current flows from the cathode (P-type silicon) to the anode (N-type). A diode and a resistor on the chip. The chip uses 16 resistors, located in the middle of the die. A resistor is constructed from a long, thin region of doped silicon. Since silicon has moderately high resistance, a long strip of silicon acts as a resistor. Most of the resistors have a serpentine layout to fit a long resistor into a smaller area. These resistors consist of P-type silicon (green) in a "tub" of N-type silicon (red). The tub is connected to the positive voltage supply; since current doesn't flow from N-type silicon to P-type silicon, this isolates the resistors from each other. Operation of a DTL gate Logic gates can be created in many ways. The earliest integrated circuits (such as the ones in the Apollo Guidance Computer) used Resistor-Transistor Logic (RTL), where logic gates were constructed from resistors and transistors. In March 1962, Signetics announced the first family of commercial Diode-Transistor Logic (DTL) integrated circuits (details). By using diodes on the inputs instead of resistors, DTL provided better performance than RTL. However, DTL soon became overshadowed by TTL (Transistor-Transistor Logic), which was faster and used less power. (If you built digital circuits a few decades ago, you're probably familiar with the popular 7400 series of TTL chips.) The diagram below shows how the DTL NAND gate works. If both inputs are high, the current from the first resistor flows through the base of the first transistor, turning it on. The transistor amplifies this current, passing a much larger current from the transistor's collector to the transistor's emitter. This current goes through the base of the second transistor, which turns on the second transistor. The second transistor passes an even larger current from the output pin to ground, pulling the output pin low. The DTL NAND gate with both inputs high. The schematic is from the datasheet. This circuit is considerably more complicated than the DTL gate on Wikipedia. But if one of the input pins is pulled low, the current from the resistor goes through the diode instead of the transistor. The first transistor turns off, and without a base current, the second transistor turns off. The third resistor pulls the output high. Thus, the output is low only if both inputs are high: a NAND gate. The DTL NAND gate with an input low. I'll point out a few features of this circuit. The diodes on the inputs ensure that one input doesn't affect the other input. The diode in the middle raises the voltage on the first transistor's emitter, so it requires more voltage to turn on, reducing the sensitivity to noise. The output uses a resistor to pull the output high; more advanced circuits use another transistor. When the output is low, the third resistor is still "trying" to pull the output high, which is wasting power. Moreover, the resistor limits the output current, so the high output is fairly weak. In some DTL families, you can get gates with different values for the output resistor, so you can select the tradeoff between wasting power and having an output that is too weak. If you've used TTL integrated circuits from the 1970s, you know that chips usually have power and ground on diagonal pins: ground on pin 7 and power on pin 14. (Putting power and ground diagonally opposite both helps die layout and circuit board layout.) Much to my surprise, I found that the Signetics chips predate this standard and have ground on pin 1 and power on pin 8: still diagonal, but the wrong diagonal! The diagram below shows how the four NAND gates are wired in the chip. Pinout of the 680A quad NAND gate. From the databook. Three chips from one die When I examined the die under the microscope, I figured out the circuit, but I was puzzled by two extra diodes, as if two NAND gates had a third input that wasn't used. The explanation is that Signetics used the same silicon layout for at least three different chips, applying a different metal layer for different functionality. This saved money since it's much cheaper to produce a single optical mask for the metal layer than a complete set of new masks. Signetics sold semi-custom ICs to customers, using an approach called variFEBS (Variable Functional Electronics Blocks). This approach used a custom metal layer on top of fixed silicon, providing custom circuits without the cost of a full mask set. These circuits didn't sell well, but Signetics used the same approach for standard ICs. Pinout of the 670A triple NAND gate and the 616A quad NAND gate. All three chips have some similarities, such as using pins 2 and 14 as outputs. From the databook. One IC with the same silicon as the quad NAND gate is the 670A chip, which has three NAND gates, each with three inputs (above left). The diagram below shows how the silicon can be wired to provide this functionality. The hypothesized metal layer for the 670A triple-NAND gate. The layout for the triple chip above is a bit tricky because the top gate has inputs on both sides of the power (Vcc) pin. This creates a layout problem because the power and ground metal runs vertically to the resistors, blocking metal wiring from one side to the other. The solution is a "crossunder", a region of silicon that allows a signal to pass under the metal layer, connecting the inputs on the left to the rest of the circuitry on the right. This crossunder is visible near the top of the chip. Another chip with the same layout is the 616A dual NAND gate, with five inputs on each gate. Since this chip has 10 inputs in total (compared to 8 on the quad gate), this chip uses the two "extra" diodes that I spotted. If that isn't enough inputs, each NAND gate has an expansion input; by connecting external diodes to the expansion input, the gate can be made as large as desired. The hypothesized metal layer for the 616A dual-NAND chip. Some history The history of Signetics is closely tied to Fairchild. The story of Fairchild's founding is well known: in 1957, eight engineers—the Traitorous Eight—left Shockley Semiconductor and created Fairchild Semiconductor. Hundreds of companies (the "Fairchildren") were started by engineers who left Fairchild. Signetics was one of those companies, formed in 1961 and said to be the first company to exclusively design and manufacture integrated circuits.2 Signetics announced its first product in 1962, a NAND gate that cost $125 (over $1000 in current dollars).3 Not surprisingly, sales were weak. Signetics soon ran short of money, so in 1962, Corning Glass invested $1.7 million for 51% ownership of Signetics. Corning Glass may seem like a strange investor, but Corning was more of a high-tech company than you'd expect, making components such as resistors and glass capacitors, and later creating fiber optics. Moreover, in the early 1960s, integrated circuits were the hot area (much like AI now), and everyone wanted to get involved. In 1963, the Department of Defense pushed for contractors to use integrated circuits in new products. Riding this wave, Signetics became the leading producer of integrated circuits.4 However, Fairchild soon introduced a series of DTL chips that competed with Signetics. The Fairchild 930 series was faster than the Signetics chips and less than half the price, so Fairchild took much of the market from Signetics and dominated the IC market. Signetics also produced analog integrated circuits. Signetics is probably best known for creating the 555 timer chip in 1970, said to be the world's most popular IC, with billions sold.5 Signetics was acquired by Philips in 1975, and then Philips Semiconductors was spun off as NXP (Next exPerience) in 2006. NXP is currently the #10 semiconductor manufacturer worldwide, so the heritage of Signetics lives on. For more, follow me on Bluesky (@righto.com), Mastodon (@[email protected]), or RSS. Thanks to CuriousMarc for providing the IC and thanks to TubeTime for finding the databook. AI statement: Despite the presence of the em dash, no AI was used in the writing of this article (details). Notes and references After I had reverse-engineered the chip, TubeTime found datasheets for it, making my reverse engineering unnecessary. (See the Signetics Condensed Catalog 1969, Utilogic II Databook 1971, and Utilogic 2 Databook 1972.) We must have been unlucky with our original web searches since we didn't find anything. But this way you get to see what's inside the chip :-) The Signetics ST680A IC in its package. The large circular depression marks pin 1. From the date code, this chip is from 1971.  ↩ For more Signetics history, see Signetics Founding History, written by Lionel Kattner, a co-founder of Signetics. He states that the company name was inspired by the words "signals" and "networks", as well as the high-tech suffix "-netics". ↩ See History of Semiconductor Engineering, page 156. ↩ The book Making Silicon Valley describes the history of Signetics. It has a negative view of the Corning investment, saying that Signetics executives "Van Poppelen and Kattner dissented on the grounds that Corning was not a good fit for an integrated circuit company. In their view, Corning was a staid Eastern firm, ignorant about semiconductors and antithetic to the ways and culture of the electronics industry on the West Coast. Their view later proved to be correct." ↩ The 555 timer was created by analog IC wizard Hans Camenzind. If you're interested in analog circuits, you should read his book Designing Analog Chips, which you can download for free. ↩

2 days ago • 1 votes
📚 BoredReading

You seem to be enjoying this.

Join free to unlock everything.

Create free account

Already have an account? Sign in